在 ASP .NET Core Web API 请求期间检查用户声明
Check user claims during request in ASP .NET Core Web API
我在 Startup.cs
中定义了政策:
services.AddAuthorization(options =>
{
options.AddPolicy(PolicyTypes.Engines.Get, policy =>
{
policy.RequireClaim(CustomClaimTypes.Permission, Permissions.Engines.Get);
});
options.AddPolicy(PolicyTypes.Engines.Manage, policy =>
{
policy.RequireClaim(CustomClaimTypes.Permission, Permissions.Engines.Manage);
});
});
权限class:
public static class Permissions
{
public static class Engines
{
public const string Manage = "engines.manage";
public const string Get = "engines.get";
}
}
后来我用定义的策略在控制器中实现了端点。
[Authorize(Policy = PolicyTypes.Engines.Get)]
[HttpGet(Name = "Engines")]
public IEnumerable<Engine> GetAll()
{
IEnumerable<Engine> engines = repository.GetAll<Engine>();
return engines;
}
我使用不记名令牌通过邮递员进行测试,以检查对此端点的访问。测试用户有策略 PolicyTypes.Engines.Manage
。解码令牌的结果。
{
"sub": "test@test.com",
"email": "test@test.com",
"claims": [
{
"Issuer": "LOCAL AUTHORITY",
"OriginalIssuer": "LOCAL AUTHORITY",
"Properties": {},
"Subject": null,
"Type": "projectname/permission",
"Value": "engines.manage",
"ValueType": "http://www.w3.org/2001/XMLSchema#string"
},
{
"Issuer": "LOCAL AUTHORITY",
"OriginalIssuer": "LOCAL AUTHORITY",
"Properties": {},
"Subject": null,
"Type": "http://schemas.microsoft.com/ws/2008/06/identity/claims/role",
"Value": "Constructor",
"ValueType": "http://www.w3.org/2001/XMLSchema#string"
}
],
"iss": "dotnet_TEST",
"aud": "TEST",
"nbf": 1534023667,
"iat": 1534023667,
"exp": 1534027267
}
当我执行请求时,我得到代码 200 和结果 json 形式的端点。我没有收到 403 forbidden 的原因是什么?
我提供生成令牌的代码。
private async Task<List<Claim>> GetValidClaims(User user)
{
IdentityOptions _options = new IdentityOptions();
var claims = new List<Claim>
{
new Claim(JwtRegisteredClaimNames.Sub, user.UserName),
new Claim(JwtRegisteredClaimNames.Jti, await options.JtiGenerator()),
new Claim(JwtRegisteredClaimNames.Iat, ToUnixEpochDate(options.IssuedAt).ToString(), ClaimValueTypes.Integer64),
new Claim(_options.ClaimsIdentity.UserIdClaimType, user.Id.ToString()),
new Claim(_options.ClaimsIdentity.UserNameClaimType, user.UserName)
};
var userClaims = await userManager.GetClaimsAsync(user);
var userRoles = await userManager.GetRolesAsync(user);
claims.AddRange(userClaims);
//foreach (var userRole in userRoles)
//{
// claims.Add(new Claim(ClaimTypes.Role, userRole));
// var role = await roleManager.FindByNameAsync(userRole);
// if (role != null)
// {
// var roleClaims = await roleManager.GetClaimsAsync(role);
// foreach (Claim roleClaim in roleClaims)
// {
// claims.Add(roleClaim);
// }
// }
//}
return claims;
}
public async Task<string> GenerateEncodedToken(User user)
{
IEnumerable<Claim> claims = await this.GetValidClaims(user);
var jwt = new JwtSecurityToken(
issuer: options.Issuer,
audience: options.Audience,
claims: claims,
notBefore: options.NotBefore,
expires: options.Expiration,
signingCredentials: options.SigningCredentials);
var encodedJwt = new JwtSecurityTokenHandler().WriteToken(jwt);
return encodedJwt;
}
在 JSON Web 令牌中,声明直接编码为 JWT 负载的一部分。 Claim
type 的附加信息未在 JWT 中编码。
JWT 只关心声明类型和声明值。这些被编码为 JWT 负载的直接属性。
所以你的声明应该这样编码:
{
"sub": "test@test.com",
"email": "test@test.com",
"projectname/permission": "engines.manage",
"http://schemas.microsoft.com/ws/2008/06/identity/claims/role": "Constructor",
"iss": "dotnet_TEST",
"aud": "TEST",
"nbf": 1534023667,
"iat": 1534023667,
"exp": 1534027267
}
我在 Startup.cs
中定义了政策:
services.AddAuthorization(options =>
{
options.AddPolicy(PolicyTypes.Engines.Get, policy =>
{
policy.RequireClaim(CustomClaimTypes.Permission, Permissions.Engines.Get);
});
options.AddPolicy(PolicyTypes.Engines.Manage, policy =>
{
policy.RequireClaim(CustomClaimTypes.Permission, Permissions.Engines.Manage);
});
});
权限class:
public static class Permissions
{
public static class Engines
{
public const string Manage = "engines.manage";
public const string Get = "engines.get";
}
}
后来我用定义的策略在控制器中实现了端点。
[Authorize(Policy = PolicyTypes.Engines.Get)]
[HttpGet(Name = "Engines")]
public IEnumerable<Engine> GetAll()
{
IEnumerable<Engine> engines = repository.GetAll<Engine>();
return engines;
}
我使用不记名令牌通过邮递员进行测试,以检查对此端点的访问。测试用户有策略 PolicyTypes.Engines.Manage
。解码令牌的结果。
{
"sub": "test@test.com",
"email": "test@test.com",
"claims": [
{
"Issuer": "LOCAL AUTHORITY",
"OriginalIssuer": "LOCAL AUTHORITY",
"Properties": {},
"Subject": null,
"Type": "projectname/permission",
"Value": "engines.manage",
"ValueType": "http://www.w3.org/2001/XMLSchema#string"
},
{
"Issuer": "LOCAL AUTHORITY",
"OriginalIssuer": "LOCAL AUTHORITY",
"Properties": {},
"Subject": null,
"Type": "http://schemas.microsoft.com/ws/2008/06/identity/claims/role",
"Value": "Constructor",
"ValueType": "http://www.w3.org/2001/XMLSchema#string"
}
],
"iss": "dotnet_TEST",
"aud": "TEST",
"nbf": 1534023667,
"iat": 1534023667,
"exp": 1534027267
}
当我执行请求时,我得到代码 200 和结果 json 形式的端点。我没有收到 403 forbidden 的原因是什么?
我提供生成令牌的代码。
private async Task<List<Claim>> GetValidClaims(User user)
{
IdentityOptions _options = new IdentityOptions();
var claims = new List<Claim>
{
new Claim(JwtRegisteredClaimNames.Sub, user.UserName),
new Claim(JwtRegisteredClaimNames.Jti, await options.JtiGenerator()),
new Claim(JwtRegisteredClaimNames.Iat, ToUnixEpochDate(options.IssuedAt).ToString(), ClaimValueTypes.Integer64),
new Claim(_options.ClaimsIdentity.UserIdClaimType, user.Id.ToString()),
new Claim(_options.ClaimsIdentity.UserNameClaimType, user.UserName)
};
var userClaims = await userManager.GetClaimsAsync(user);
var userRoles = await userManager.GetRolesAsync(user);
claims.AddRange(userClaims);
//foreach (var userRole in userRoles)
//{
// claims.Add(new Claim(ClaimTypes.Role, userRole));
// var role = await roleManager.FindByNameAsync(userRole);
// if (role != null)
// {
// var roleClaims = await roleManager.GetClaimsAsync(role);
// foreach (Claim roleClaim in roleClaims)
// {
// claims.Add(roleClaim);
// }
// }
//}
return claims;
}
public async Task<string> GenerateEncodedToken(User user)
{
IEnumerable<Claim> claims = await this.GetValidClaims(user);
var jwt = new JwtSecurityToken(
issuer: options.Issuer,
audience: options.Audience,
claims: claims,
notBefore: options.NotBefore,
expires: options.Expiration,
signingCredentials: options.SigningCredentials);
var encodedJwt = new JwtSecurityTokenHandler().WriteToken(jwt);
return encodedJwt;
}
在 JSON Web 令牌中,声明直接编码为 JWT 负载的一部分。 Claim
type 的附加信息未在 JWT 中编码。
JWT 只关心声明类型和声明值。这些被编码为 JWT 负载的直接属性。
所以你的声明应该这样编码:
{
"sub": "test@test.com",
"email": "test@test.com",
"projectname/permission": "engines.manage",
"http://schemas.microsoft.com/ws/2008/06/identity/claims/role": "Constructor",
"iss": "dotnet_TEST",
"aud": "TEST",
"nbf": 1534023667,
"iat": 1534023667,
"exp": 1534027267
}