0

aspnetコアWebアプリケーションのアクセストークンを生成しようとしています。AspNet.Security.OpenIdConnect.Serverを使用すると、ユーザーは常にnullです。

public class CustomOpenIdConnectServerProvider : OpenIdConnectServerProvider 
    { 
     public override Task ValidateTokenRequest(ValidateTokenRequestContext context) 
     { 
      // Reject the token requests that don't use grant_type=password or grant_type=refresh_token. 
      if (!context.Request.IsPasswordGrantType() && !context.Request.IsRefreshTokenGrantType()) 
      { 
       context.Reject(
        error: OpenIdConnectConstants.Errors.UnsupportedGrantType, 
        description: "Only the resource owner password credentials and refresh token " + 
           "grants are accepted by this authorization server"); 

       return Task.FromResult(0); 
      } 

      // Since there's only one application and since it's a public client 
      // (i.e a client that cannot keep its credentials private), call Skip() 
      // to inform the server the request should be accepted without 
      // enforcing client authentication. 
      context.Skip(); 

      return Task.FromResult(0); 
     } 

     public override async Task HandleTokenRequest(HandleTokenRequestContext context) 
     { 
      // Resolve ASP.NET Core Identity's user manager from the DI container. 
      var manager = context.HttpContext.RequestServices.GetRequiredService<UserManager<User>>(); 

      // Only handle grant_type=password requests and let ASOS 
      // process grant_type=refresh_token requests automatically. 
      if (context.Request.IsPasswordGrantType()) 
      { 
       var user = await manager.FindByNameAsync(context.Request.Username); 
       if (user == null) 
       { 
        context.Reject(
         error: OpenIdConnectConstants.Errors.InvalidGrant, 
         description: "Invalid credentials."); 

        return; 
       } 

       // Ensure the password is valid. 
       if (!await manager.CheckPasswordAsync(user, context.Request.Password)) 
       { 
        if (manager.SupportsUserLockout) 
        { 
         await manager.AccessFailedAsync(user); 
        } 

        context.Reject(
         error: OpenIdConnectConstants.Errors.InvalidGrant, 
         description: "Invalid credentials."); 

        return; 
       } 

       if (manager.SupportsUserLockout) 
       { 
        await manager.ResetAccessFailedCountAsync(user); 
       } 

       var identity = new ClaimsIdentity(context.Options.AuthenticationScheme); 

       // Note: the name identifier is always included in both identity and 
       // access tokens, even if an explicit destination is not specified. 
       identity.AddClaim(ClaimTypes.NameIdentifier, await manager.GetUserIdAsync(user)); 

       identity.AddClaim(OpenIdConnectConstants.Claims.Subject, await manager.GetUserIdAsync(user)); 

       // When adding custom claims, you MUST specify one or more destinations. 
       // Read "part 7" for more information about custom claims and scopes. 
       identity.AddClaim("username", await manager.GetUserNameAsync(user), 
        OpenIdConnectConstants.Destinations.AccessToken, 
        OpenIdConnectConstants.Destinations.IdentityToken); 

       var claims = await manager.GetClaimsAsync(user); 
       foreach (var claim in claims) 
       { 
        identity.AddClaim(claim.Type, claim.Value, OpenIdConnectConstants.Destinations.AccessToken, 
         OpenIdConnectConstants.Destinations.IdentityToken); 
       } 

       // Create a new authentication ticket holding the user identity. 
       var ticket = new AuthenticationTicket(
        new ClaimsPrincipal(identity), 
        new AuthenticationProperties(), 
        context.Options.AuthenticationScheme); 


       // Set the list of scopes granted to the client application. 
       ticket.SetScopes(
        /* openid: */ OpenIdConnectConstants.Scopes.OpenId, 
        OpenIdConnectConstants.Scopes.OfflineAccess, 
        /* email: */ OpenIdConnectConstants.Scopes.Email, 
        /* profile: */ OpenIdConnectConstants.Scopes.Profile); 

       // Set the resource servers the access token should be issued for. 
       ticket.SetResources("resource_server"); 

       context.Validate(ticket); 
      } 
     } 

これは問題なく動作し、アクセストークンを取得でき、ユーザーは正常に認証されます。私がここで直面している問題は、私がこれを行うときに承認されたアクションメソッドでそれは:var user = await _userManager.GetUserAsync(User);userの値は常にnullです!もちろん、私は有効なアクセストークンを持つAuthorizationヘッダーを渡しています。要求はAuthorizeと注釈が付けられた動作に問題なく入ります。 userの値はnullです。誰も私のコードで何が間違っているか教えてもらえますか?

答えて

2

デフォルトでは、UserManager.GetUserAsync(User)は、ClaimTypes.NameIdentifierクレームをユーザー識別子として使用します。

ClaimTypes.NameIdentifierは、もはやOpenID Connectサーバーミドルウェアによって1.0の特別クレームとみなされませんが、適切な宛先がないためアクセストークンに追加されません。その結果、Identityはアクセストークンからユーザー識別子を抽出できません。

あなたはそれを修正するための3つのオプションがあります:

  • は、あなたのStartup.ConfigureServices()方法でservices.Configure<IdentityOptions>(options => options.ClaimsIdentity.UserIdClaimType = OpenIdConnectConstants.Claims.Subject);を呼び出すことにより、アイデンティティーが使用するデフォルトのユーザ識別子の主張を交換してください。

  • ClaimTypes.NameIdentifierクレームを使用してくださいが、正しい宛先(OpenIdConnectConstants.Destinations.AccessToken)を指定してください。

  • UserManager.GetUserAsync(User)の代わりにUserManager.FindByIdAsync(User.FindFirstValue(OpenIdConnectConstants.Claims.Subject))を使用してください。

関連する問題