Asp.net mvc 使用AspNet.Security.OpenIdConnect.Server时,用户始终为空

Asp.net mvc 使用AspNet.Security.OpenIdConnect.Server时,用户始终为空,asp.net-mvc,asp.net-core,openid,openid-connect,openid-provider,Asp.net Mvc,Asp.net Core,Openid,Openid Connect,Openid Provider,我正在尝试为我的aspnet核心web应用程序生成访问令牌。我创建了以下提供程序: public class CustomOpenIdConnectServerProvider : OpenIdConnectServerProvider { public override Task ValidateTokenRequest(ValidateTokenRequestContext context) { // Reject the to

我正在尝试为我的aspnet核心web应用程序生成访问令牌。我创建了以下提供程序:

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);
            }
        }
公共类CustomOpenIdConnectServerProvider:OpenIdConnectServerProvider { 公共覆盖任务ValidateTokenRequest(ValidateTokenRequestContext上下文) { //拒绝不使用grant\u type=password或grant\u type=refresh\u令牌的令牌请求。 如果(!context.Request.IsPasswordGrantType()&&!context.Request.IsRefreshTokenGrantType()) { 上下文。拒绝( 错误:OpenIdConnectConstants.Errors.UnsupportedGrantType, 描述:“仅资源所有者密码凭据和刷新令牌”+ “此授权服务器接受授权”); 返回Task.FromResult(0); } //因为只有一个应用程序,而且它是一个公共客户端 //(即无法将其凭据保持为私有的客户端),调用Skip() //若要通知服务器,应接受请求,而无需 //强制客户端身份验证。 context.Skip(); 返回Task.FromResult(0); } 公共重写异步任务HandleTokenRequest(HandleTokenRequestContext) { //从DI容器解析ASP.NET核心标识的用户管理器。 var manager=context.HttpContext.RequestServices.GetRequiredService(); //仅处理授权类型=密码请求,并允许ASO //处理授权\类型=自动刷新\令牌请求。 if(context.Request.IsPasswordGrantType()) { var user=await manager.FindByNameAsync(context.Request.Username); if(user==null) { 上下文。拒绝( 错误:OpenIdConnectConstants.Errors.InvalidGrant, 说明:“无效凭据。”); 返回; } //确保密码有效。 if(!wait manager.CheckPasswordAsync(用户、上下文、请求、密码)) { if(经理支持SUSERLOCKOUT) { 等待manager.AccessFailedAsync(用户); } 上下文。拒绝( 错误:OpenIdConnectConstants.Errors.InvalidGrant, 说明:“无效凭据。”); 返回; } if(经理支持SUSERLOCKOUT) { 等待manager.ResetAccessFailedCountAsync(用户); } var identity=newclaimsidentity(context.Options.AuthenticationScheme); //注意:名称标识符始终包含在标识和 //访问令牌,即使未指定显式目标。 AddClaim(ClaimTypes.NameIdentifier,wait manager.GetUserIdAsync(user)); identity.AddClaim(OpenIdConnectConstants.Claims.Subject,wait manager.GetUserIdAsync(user)); //添加自定义声明时,必须指定一个或多个目标。 //有关自定义声明和范围的更多信息,请阅读“第7部分”。 identity.AddClaim(“用户名”),wait manager.GetUserNameAsync(用户), OpenIdConnectConstants.Destinations.AccessToken, OpenIdConnectConstants.Destinations.IdentityToken); var claims=await manager.GetClaimsAsync(用户); foreach(索赔中的var索赔) { identity.AddClaim(claim.Type、claim.Value、OpenIdConnectConstants.Destinations.AccessToken、, OpenIdConnectConstants.Destinations.IdentityToken); } //创建包含用户标识的新身份验证票证。 var票证=新的身份验证票证( 新索赔人(身份), 新建AuthenticationProperties(), context.Options.AuthenticationScheme); //设置授予客户端应用程序的作用域列表。 检票镜( /*openid://OpenIdConnectConstants.Scopes.openid, OpenIdConnectConstants.Scopes.OfflineAccess, /*电子邮件:*/OpenIdConnectConstants.Scopes.email, /*概要文件:*/OpenIdConnectConstants.Scopes.profile); //设置应为其颁发访问令牌的资源服务器。 ticket.SetResources(“资源_服务器”); 验证(票证); } }
这很好,我可以获得访问令牌,并且成功地对用户进行身份验证。我在这里面临的问题是,在我执行此操作时,在任何授权操作方法中:
var user=wait\u userManager.GetUserAsync(user)
user
的值总是空的!当然,我正在传递带有有效访问令牌的授权头,请求进入带有
Authorize
注释的操作,没有任何问题。只是
user
的值是空的。有人能告诉我我的代码有什么问题吗?

默认情况下,
userManager.GetUserAsync(User)
使用
ClaimTypes.NameIdentifier
声明作为用户标识符

在您的情况下,
ClaimTypes.NameIdentifier
(OpenID Connect server中间件不再将其视为1.0中的特殊声明)不会添加到访问令牌中,因为它没有适当的目标。因此,Identity无法从访问令牌中提取用户标识符

您有3个选项可以解决此问题:<