Asp.net mvc 使用AspNet.Security.OpenIdConnect.Server时,用户始终为空
我正在尝试为我的aspnet核心web应用程序生成访问令牌。我创建了以下提供程序: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
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个选项可以解决此问题:<