5

我是一個stackoverflow noob,所以如果我這樣做錯了,請儘量輕鬆。asp.net核心身份提取並保存外部登錄令牌並將聲明添加到本地身份

我使用默認的核心身份模板(本地帳戶)的asp.net核心。

我已經accertained如何索賠添加到用戶主體時,他們在本地登錄,像這樣

[HttpPost] 
    [AllowAnonymous] 
    [ValidateAntiForgeryToken] 
    public async Task<IActionResult> Login(LoginInputModel model) 
    { 
     if (ModelState.IsValid) 
     { 
      // This doesn't count login failures towards account lockout 
      // To enable password failures to trigger account lockout, set lockoutOnFailure: true 

      var user = await _userManager.FindByNameAsync(model.Email); 

      await _userManager.AddClaimAsync(user, new Claim("your-claim", "your-value")); 

我想通了如何從外部登錄返回指控,但我不知道我是怎麼想補充用戶主體獲取的ExternalLoginCallback功能創造了這些前

public async Task<IActionResult> ExternalLoginCallback(string returnUrl = null, string remoteError = null) 
    { 
     if (remoteError != null) 
     { 
      ModelState.AddModelError(string.Empty, $"Error from external provider: {remoteError}"); 
      return View(nameof(Login)); 
     } 

     var info = await _signInManager.GetExternalLoginInfoAsync(); 
     if (info == null) 
     { 
      return RedirectToAction(nameof(Login)); 
     } 
     else { 
      // extract claims from external token here 
     } 

     // assume add claims to user here before cookie gets created?? 

     // 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) 

我假設的_signInManager.ExternalLoginSignInAsync功能的工作原理類似於在這個意義上本地登錄_signInManager.PasswordSignInAsync,一旦它被調用,cookie將被創建。但我不確定。

本質上,我希望實現的是瞭解如何將自定義聲明添加到創建的cookie中,而不管用戶如何登錄(本地或外部),以及如何在需要時將這些聲明持久保存到數據庫。

我打算做一些工作,如果我有一個用戶登錄使用說谷歌認證,我需要從谷歌保存access_token,因爲我希望隨後調用Google API。所以我需要能夠將這個access_token包含在創建的用戶主體中,並且我希望cookie可以在前端使用它。

這可能超出了這個問題的範圍,但我也想當谷歌令牌到期,對於某些 - 如何使用刷新令牌並去獲取新的令牌,或強制用戶重新登錄。

對此的任何幫助將超級讚賞,我真的很努力去理解這個沒有發佈這個問題到stackoverflow。我閱讀了很多有用信息的文章,但沒有提供這個具體問題所要求的答案。所以非常感謝你提前。

歡呼

回答

4

當您使用await _userManager.AddClaimAsync(user, new Claim("your-claim", "your-value"));實際更新標識的aspnetuserclaims表。

無論您何時登錄(通過使用_signInManager.PasswordSignIn或_signInManager.ExternalLoginSignInAsync),都會讀取該表中的聲明並將其添加到每個請求成爲主體的Cookie中。

因此,您可能不希望在每次登錄時都從UserManager調用AddClaimAsync方法。

關於外部登錄供應商,您可以訪問,當你調用(在ExternalCallback和ExternalCallbackConfirmation如果你使用的是默認模板)的索賠這裏:

var info = await _signInManager.GetExternalLoginInfoAsync(); 

的索賠是info.Principal.Claims

訪問令牌默認不包含在內。當是時,它會在這裏(連同類型和到期日):

var accessToken = info.AuthenticationTokens.Single(f => f.Name == "access_token").Value; 
var tokenType = info.AuthenticationTokens.Single(f => f.Name == "token_type").Value; 
var expiryDate = info.AuthenticationTokens.Single(f => f.Name == "expires_at").Value; 

若要訪問令牌包含在AuthenticationTokens集合中,當你配置GoogleAuthentication中間件SaveTokens標誌設置爲true :

 app.UseGoogleAuthentication(new GoogleOptions{ 
      ClientId = "...", 
      ClientSecret = "...", 
      SaveTokens = true 

現在,如果你想擁有超過號稱走在你要「接管」創建聲明主體的過程將Cookie控制。

這是爲您完成的,當您使用_signInManager.PasswordSignIn/ExternalLoginSignInAsync

因此,例如,對於ExternalLoginSignInAsync取代:

var result = await _signInManager.ExternalLoginSignInAsync(info.LoginProvider, info.ProviderKey, isPersistent: false); 

有了:

var user = await this._userManager.FindByLoginAsync(info.LoginProvider, info.ProviderKey); 
    var claimsPrincipal = await this._signInManager.CreateUserPrincipalAsync(user); 
    ((ClaimsIdentity)claimsPrincipal.Identity).AddClaim(new Claim("accessToken", info.AuthenticationTokens.Single(t => t.Name == "access_token").Value)); 
    await HttpContext.Authentication.SignInAsync("Identity.Application", claimsPrincipal); 

「Identity.Application」 是默認的cookie名稱。您可以在啓動的ConfigureServices方法改變它,例如MainCookie:

 services.Configure<IdentityOptions>(options => { 
      options.Cookies.ApplicationCookie.AuthenticationScheme = "MainCookie"; 
     }); 

你仍然需要以處理的AccountController的ExternalCallbackConfirmation行動。它將與上面的示例類似。