IdentityServer4:[Authorize(Roles = "Admin")] 即使 JWT 令牌具有 {"role": "Admin"} 声明也不授予管理员用户访问权限
IdentityServer4: [Authorize(Roles = "Admin")] not granting access to Admin User even when the JWT Token has {"role": "Admin"} claim
我的问题是,即使登录用户是管理员,他仍然无法访问具有 [Authorize(Roles = "Admin")]
属性的控制器。
Note: The codes works perfectly fine on postman testing but not on openid connect.
身份服务器 4
我已经设置了我的身份服务器 4,并且与 OpenId 连接配合得很好。没问题。
客户项目
有一个客户端项目只有一个 Web api,它由 [Authorize(Roles = "Admin")]
属性保护。
[ApiController]
[Route("[controller]")]
[Authorize(Roles = "Admin")]
public class WeatherForecastController : ControllerBase
{
......
}
是URL是https://localhost:5002/WeatherForecast
。
现在:我在浏览器中打开这个安全 URL,我被重定向到 IdnentityServer 登录页面,我在其中输入管理员用户的用户名和密码。
之后发生的事情是我被重定向到 https://localhost:5002/Account/AccessDenied?ReturnUrl=%2FWeatherForecast
页面(这不应该是因为用户具有管理员角色)。
在控制台上我收到错误 -
Authorization failed. These requirements were not met:
RolesAuthorizationRequirement:User.IsInRole must be true for one of
the following roles: (Admin)
在 jwt 网站上解码令牌时,我可以清楚地看到 "role": "Admin"
那里。见下图:
所以我可以说我的令牌上有管理员角色声明,因此它应该能够访问安全控制器。 但是没有发生??
如果我从属性属性中删除角色 - [Authorize]
那么我就可以使用令牌访问控制器。见下图:
代码:
startup.cs ConfigureServices 方法是我添加 Openid 连接代码的地方:
services.AddAuthentication(options =>
{
options.DefaultScheme = "Cookies";
options.DefaultChallengeScheme = "oidc";
})
.AddCookie("Cookies")
.AddJwtBearer(options =>
{
options.Authority = "https://localhost:5001";
options.Audience = "IS4API";
})
.AddOpenIdConnect("oidc", options =>
{
options.Authority = "https://localhost:5001";
options.ClientId = "postman";
options.ResponseType = "code";
options.Scope.Add("fullaccess");
options.SaveTokens = true;
});
我不分享 IdentityServer 的代码,因为令牌正在生成 属性,我认为 IdentityServer 没有任何问题。
那么这里可能是什么问题,为什么基于角色的 IdentityServer 4 身份验证在我的案例中失败?
由于某种原因会出现此问题。请检查以下步骤。
1.The问题可以按Authentication
和Authorization
的顺序在管道中,确保Authentication
放在Authorization
之前。
2.You 必须在 Startup.cs
中添加以下代码行以启用 RoleManager。
services.AddDefaultIdentity<ApplicationUser>()
.AddRoles<IdentityRole>() // <-- Add this line
.AddEntityFrameworkStores<ApplicationDbContext>();
3.According到这个GitHub Link,把这行代码加到ConfigureServices
// Add Role claims to the User object
services.AddScoped<IUserClaimsPrincipalFactory<ApplicationUser>, UserClaimsPrincipalFactory<ApplicationUser, IdentityRole>>();
请检查所有步骤。我认为这将有助于解决您的问题。
如果它在邮递员上工作,我认为您的 openid 连接配置有问题。检查身份服务器 openid 连接 documentation
您必须将角色声明类型引入您的应用程序。在 .AddJwtBearer 选项中,有一个地方可以在令牌验证参数中设置角色声明类型:
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateAudience = false,
NameClaimType = "name",
RoleClaimType = "role"
};
然后在 IDS4 的配置文件中,为您的应用添加 Jwt 声明类型“Role”:
new ApiScope
{
Name = "myAPI",
DisplayName = "my API",
Enabled = true,
UserClaims =
{ JwtClaimTypes.Name,
JwtClaimTypes.Email,
JwtClaimTypes.Subject,
JwtClaimTypes.Role,
JwtClaimTypes.Address,
JwtClaimTypes.Confirmation,
JwtClaimTypes.EmailVerified,
JwtClaimTypes.Id,
JwtClaimTypes.Profile
}
},
我的问题是,即使登录用户是管理员,他仍然无法访问具有 [Authorize(Roles = "Admin")]
属性的控制器。
Note: The codes works perfectly fine on postman testing but not on openid connect.
身份服务器 4
我已经设置了我的身份服务器 4,并且与 OpenId 连接配合得很好。没问题。
客户项目
有一个客户端项目只有一个 Web api,它由 [Authorize(Roles = "Admin")]
属性保护。
[ApiController]
[Route("[controller]")]
[Authorize(Roles = "Admin")]
public class WeatherForecastController : ControllerBase
{
......
}
是URL是https://localhost:5002/WeatherForecast
。
现在:我在浏览器中打开这个安全 URL,我被重定向到 IdnentityServer 登录页面,我在其中输入管理员用户的用户名和密码。
之后发生的事情是我被重定向到 https://localhost:5002/Account/AccessDenied?ReturnUrl=%2FWeatherForecast
页面(这不应该是因为用户具有管理员角色)。
在控制台上我收到错误 -
Authorization failed. These requirements were not met: RolesAuthorizationRequirement:User.IsInRole must be true for one of the following roles: (Admin)
在 jwt 网站上解码令牌时,我可以清楚地看到 "role": "Admin"
那里。见下图:
所以我可以说我的令牌上有管理员角色声明,因此它应该能够访问安全控制器。 但是没有发生??
如果我从属性属性中删除角色 - [Authorize]
那么我就可以使用令牌访问控制器。见下图:
代码:
startup.cs ConfigureServices 方法是我添加 Openid 连接代码的地方:
services.AddAuthentication(options =>
{
options.DefaultScheme = "Cookies";
options.DefaultChallengeScheme = "oidc";
})
.AddCookie("Cookies")
.AddJwtBearer(options =>
{
options.Authority = "https://localhost:5001";
options.Audience = "IS4API";
})
.AddOpenIdConnect("oidc", options =>
{
options.Authority = "https://localhost:5001";
options.ClientId = "postman";
options.ResponseType = "code";
options.Scope.Add("fullaccess");
options.SaveTokens = true;
});
我不分享 IdentityServer 的代码,因为令牌正在生成 属性,我认为 IdentityServer 没有任何问题。
那么这里可能是什么问题,为什么基于角色的 IdentityServer 4 身份验证在我的案例中失败?
由于某种原因会出现此问题。请检查以下步骤。
1.The问题可以按Authentication
和Authorization
的顺序在管道中,确保Authentication
放在Authorization
之前。
2.You 必须在 Startup.cs
中添加以下代码行以启用 RoleManager。
services.AddDefaultIdentity<ApplicationUser>()
.AddRoles<IdentityRole>() // <-- Add this line
.AddEntityFrameworkStores<ApplicationDbContext>();
3.According到这个GitHub Link,把这行代码加到ConfigureServices
// Add Role claims to the User object
services.AddScoped<IUserClaimsPrincipalFactory<ApplicationUser>, UserClaimsPrincipalFactory<ApplicationUser, IdentityRole>>();
请检查所有步骤。我认为这将有助于解决您的问题。
如果它在邮递员上工作,我认为您的 openid 连接配置有问题。检查身份服务器 openid 连接 documentation
您必须将角色声明类型引入您的应用程序。在 .AddJwtBearer 选项中,有一个地方可以在令牌验证参数中设置角色声明类型:
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateAudience = false,
NameClaimType = "name",
RoleClaimType = "role"
};
然后在 IDS4 的配置文件中,为您的应用添加 Jwt 声明类型“Role”:
new ApiScope
{
Name = "myAPI",
DisplayName = "my API",
Enabled = true,
UserClaims =
{ JwtClaimTypes.Name,
JwtClaimTypes.Email,
JwtClaimTypes.Subject,
JwtClaimTypes.Role,
JwtClaimTypes.Address,
JwtClaimTypes.Confirmation,
JwtClaimTypes.EmailVerified,
JwtClaimTypes.Id,
JwtClaimTypes.Profile
}
},