我有两个应用程序:一个使用 ASP.NET MVC 构建,另一个使用 ASP.NET Core Web API。用户使用 Azure Active Directory (Azure AD) 登录到 ASP.NET MVC 应用程序。成功登录后,我会收到一个 Azure AD 令牌。我想使用此令牌来验证对 Web API 应用程序的请求。
但是,我还需要向此令牌添加自定义声明。这些声明存储在我的数据库中,我希望 API 能够访问它们。
这是我试图实现的流程:
我的数据库中有一个用于自定义声明的表
UserClaims
。如何确保 Web API 识别这些自定义声明?我需要在 MVC 和 API 应用程序中使用 IClaimsTransformation
吗?如何在从 Azure AD 检索到的令牌上正确设置这些自定义声明?
这种方法是否可行?如果可行,实现这一目标的最佳实践是什么?
附加信息:
谢谢您的指导!
我的想法是,当用户使用他们的微软帐户登录MVC应用程序后,我们已经知道他/她是谁,我们可以从数据库中获取相应的声明,然后我们可以自己生成jwt令牌,然后在API 应用程序,让我们验证自定义声明。这是我的代码。
在 MVC 应用程序中,我们可以使用下面的代码来生成具有我们所需声明的访问令牌。
public string generateJwt() {
var claims = new List<Claim>
{
new Claim(JwtRegisteredClaimNames.Name, "username1"),
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
new Claim("role","admin")
};
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("this is my custom Secret key for authentication"));
var token = new JwtSecurityToken(
issuer: "Test.com",
audience: "Test.com",
expires: DateTime.Now.AddHours(3),
claims: claims,
signingCredentials: new SigningCredentials(key, SecurityAlgorithms.HmacSha256)
);
var accessToken = new JwtSecurityTokenHandler().WriteToken(token);
return accessToken;
}
我们可以将不记名令牌添加到授权请求标头中来调用API。在API项目中,我们应该添加jwt auth方案,并在安全操作方法之前添加
[Authorize(Policy = "RequireAdmin")]
属性。
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Authorization;
using Microsoft.IdentityModel.Tokens;
using System.Text;
using WebApiJwt.Services;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = false,
ValidateAudience = false,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = "Test.com",
ValidAudience = "Test.com",
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("this is my custom Secret key for authentication")),
ClockSkew = TimeSpan.Zero
};
});
builder.Services.AddSingleton<IAuthorizationHandler, RoleTokenHandler>();
builder.Services.AddAuthorization(options =>
{
options.AddPolicy("RequireAdmin", policy =>
policy.Requirements.Add(new RoleRequirement("admin")));
});
builder.Services.AddControllers();
这里是相关的验证方法,可以参考asp.net core中的policy based auth方案。
namespace WebApiJwt.Services
{
public class RoleTokenHandler : AuthorizationHandler<RoleRequirement>
{
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, RoleRequirement requirement)
{
if (context != null)
{
var httpContext = (DefaultHttpContext)context.Resource;
if (httpContext != null)
{
string jwtToken = httpContext.Request.Headers["Authorization"].ToString();
jwtToken = jwtToken.Substring(7, jwtToken.Length -7);
JwtSecurityToken token = DecryptToken(jwtToken);
var claims = token.Claims;
if (token.Claims.Where(c => c.Type == "role" && c.Value == requirement.MyRole).Count() > 0)
context.Succeed(requirement);
else
{
context.Fail();
//context.Fail();
//context.Succeed(requirement);
//throw new NullReferenceException("my custom message");
}
}
else
context.Fail();
}
return Task.CompletedTask;
}
public JwtSecurityToken DecryptToken(string token)
{
var handler = new JwtSecurityTokenHandler();
var jwtSecurityToken = handler.ReadJwtToken(token);
return jwtSecurityToken;
}
}
public class RoleRequirement : IAuthorizationRequirement
{
public RoleRequirement(string role) =>
MyRole = role;
public string MyRole { get; }
}
}