2016-01-15 75 views
1

我正在使用AngularJs處理OpenIddict的示例應用程序。我被告知,你不應該使用像Satellizer這樣的客戶端框架,因爲這不是建議的,而是允許服務器處理登錄服務器端(本地和使用外部登錄提供程序),並返回訪問令牌。OpenIddict - 如何獲取用戶的訪問令牌?

那麼我有一個演示angularJs應用程序,並使用服務器端登錄邏輯和調用回角應用程序,但我的問題是,我如何獲得當前用戶的訪問令牌?

這裏是我的startup.cs文件,所以你可以看到我的配置到目前爲止

public void ConfigureServices(IServiceCollection services) { 
    var configuration = new ConfigurationBuilder() 
     .AddJsonFile("config.json") 
     .AddEnvironmentVariables() 
     .Build(); 

    services.AddMvc(); 

    services.AddEntityFramework() 
     .AddSqlServer() 
     .AddDbContext<ApplicationDbContext>(options => 
      options.UseSqlServer(configuration["Data:DefaultConnection:ConnectionString"])); 

    services.AddIdentity<ApplicationUser, IdentityRole>() 
     .AddEntityFrameworkStores<ApplicationDbContext>() 
     .AddDefaultTokenProviders() 
     .AddOpenIddict(); 

    services.AddTransient<IEmailSender, AuthMessageSender>(); 
    services.AddTransient<ISmsSender, AuthMessageSender>(); 
} 

public void Configure(IApplicationBuilder app, IHostingEnvironment env) 
{ 
    env.EnvironmentName = "Development"; 

    var factory = app.ApplicationServices.GetRequiredService<ILoggerFactory>(); 
    factory.AddConsole(); 
    factory.AddDebug(); 

    app.UseDeveloperExceptionPage(); 

    app.UseIISPlatformHandler(options => { 
     options.FlowWindowsAuthentication = false; 
    }); 

    app.UseOverrideHeaders(options => { 
     options.ForwardedOptions = ForwardedHeaders.All; 
    }); 

    app.UseStaticFiles(); 

    // Add a middleware used to validate access 
    // tokens and protect the API endpoints. 
    app.UseOAuthValidation(); 

    // comment this out and you get an error saying 
    // InvalidOperationException: No authentication handler is configured to handle the scheme: Microsoft.AspNet.Identity.External 
    app.UseIdentity(); 

    // TOO: Remove 
    app.UseGoogleAuthentication(options => { 
     options.ClientId = "XXX"; 
     options.ClientSecret = "XXX"; 
    }); 

    app.UseTwitterAuthentication(options => { 
     options.ConsumerKey = "XXX"; 
     options.ConsumerSecret = "XXX"; 
    }); 

    // Note: OpenIddict must be added after 
    // ASP.NET Identity and the external providers. 
    app.UseOpenIddict(options => 
    { 
     options.Options.AllowInsecureHttp = true; 
     options.Options.UseJwtTokens(); 
    }); 

    app.UseMvcWithDefaultRoute(); 

    using (var context = app.ApplicationServices.GetRequiredService<ApplicationDbContext>()) { 
     context.Database.EnsureCreated(); 

     // Add Mvc.Client to the known applications. 
     if (!context.Applications.Any()) { 
      context.Applications.Add(new Application { 
       Id = "myClient", 
       DisplayName = "My client application", 
       RedirectUri = "http://localhost:5000/signin", 
       LogoutRedirectUri = "http://localhost:5000/", 
       Secret = Crypto.HashPassword("secret_secret_secret"), 
       Type = OpenIddictConstants.ApplicationTypes.Confidential 
      }); 

      context.SaveChanges(); 
     } 
    } 
} 

現在我的AccountController基本上是一樣的正常賬戶控制器,雖然一度在用戶已登錄(使用本地和外部登錄)我使用這個功能,需要一個accessToken。

private IActionResult RedirectToAngular() 
{ 
    // I need the accessToken here 

    return RedirectToAction(nameof(AccountController.Angular), new { accessToken = token }); 
} 

你可以從ExternalLoginCallback方法上看到的AccountController

public async Task<IActionResult> ExternalLoginCallback(string returnUrl = null) 
{ 
    var info = await _signInManager.GetExternalLoginInfoAsync(); 
    if (info == null) 
    { 
     return RedirectToAction(nameof(Login)); 
    } 

    // Sign in the user with this external login provider if the user already has a login. 
    var result = await _signInManager.ExternalLoginSignInAsync(info.LoginProvider, info.ProviderKey, isPersistent: false); 
    if (result.Succeeded) 
    { 
     // SHOULDNT THE USER HAVE A LOCAL ACCESS TOKEN NOW?? 
     return RedirectToAngular(); 
    } 
    if (result.RequiresTwoFactor) 
    { 
     return RedirectToAction(nameof(SendCode), new { ReturnUrl = returnUrl }); 
    } 
    if (result.IsLockedOut) 
    { 
     return View("Lockout"); 
    } 
    else { 
     // If the user does not have an account, then ask the user to create an account. 
     ViewData["ReturnUrl"] = returnUrl; 
     ViewData["LoginProvider"] = info.LoginProvider; 
     var email = info.ExternalPrincipal.FindFirstValue(ClaimTypes.Email); 
     return View("ExternalLoginConfirmation", new ExternalLoginConfirmationViewModel { Email = email }); 
    } 
} 

回答

2
var result = await _signInManager.ExternalLoginSignInAsync(info.LoginProvider, info.ProviderKey, isPersistent: false); 
if (result.Succeeded) 
{ 
    // SHOULDNT THE USER HAVE A LOCAL ACCESS TOKEN NOW?? 
    return RedirectToAngular(); 
} 

,它是如何工作的不是。下面是經典的流量會發生什麼:

  • 的OAuth2用戶/ ID連接的客戶端應用程序(在你的情況,你的Satellizer JS應用程序)重定向的所有用戶代理的授權端點(/connect/authorize默認情況下OpenIddict)強制性參數:client_idredirect_uri(在OpenID Connect中是強制性的),response_typenonce使用隱式流程時(即response_type=id_token token)。假設你已經正確地註冊了授權服務器(1),衛星應該爲你做這件事。

  • 如果用戶還沒有登錄,授權端點將用戶重定向到登錄端點(在OpenIddict中,它由內部控制器爲您完成)。此時,您的AccountController.Login操作被調用,用戶將顯示一個登錄表單。

  • 當用戶登錄後(在註冊過程和/或外部認證協會之後),他/她必須重定向回授權端點:您無法將用戶代理重定向到您的Angular應用程序在這個階段。撤消對ExternalLoginCallback所做的更改,它應該可以工作。

  • 然後,用戶顯示一份同意書表明他/她將允許您的JS應用程序以他/她的名義訪問他的個人數據。當用戶提交同意書時,請求由OpenIddict處理,生成訪問令牌並將用戶代理重定向回JS客戶端應用程序,將令牌附加到URI片段。

[1]:根據Satellizer文檔,它應該是類似的東西:

$authProvider.oauth2({ 
    name: 'openiddict', 
    clientId: 'myClient', 
    redirectUri: window.location.origin + '/done', 
    authorizationEndpoint: window.location.origin + '/connect/authorize', 
    responseType: 'id_token token', 
    scope: ['openid'], 
    requiredUrlParams: ['scope', 'nonce'], 
    nonce: function() { return "TODO: implement appropriate nonce generation and validation"; }, 
    popupOptions: { width: 1028, height: 529 } 
}); 
相關問題