如何使用 Azure AD 令牌和 ASP.NET MVC 应用程序中的自定义声明对 ASP.NET Core Web API 进行身份验证?

问题描述 投票:0回答:1

我有两个应用程序:一个使用 ASP.NET MVC 构建,另一个使用 ASP.NET Core Web API。用户使用 Azure Active Directory (Azure AD) 登录到 ASP.NET MVC 应用程序。成功登录后,我会收到一个 Azure AD 令牌。我想使用此令牌来验证对 Web API 应用程序的请求。

但是,我还需要向此令牌添加自定义声明。这些声明存储在我的数据库中,我希望 API 能够访问它们。

这是我试图实现的流程:

  1. 用户使用 Azure AD 登录 MVC 应用程序
  2. 我从 Azure AD 检索令牌
  3. 我将数据库中的自定义声明添加到此令牌中
  4. Web API 使用 Azure AD 令牌进行身份验证并访问自定义声明

我的数据库中有一个用于自定义声明的表

UserClaims
。如何确保 Web API 识别这些自定义声明?我需要在 MVC 和 API 应用程序中使用
IClaimsTransformation
吗?如何在从 Azure AD 检索到的令牌上正确设置这些自定义声明?

这种方法是否可行?如果可行,实现这一目标的最佳实践是什么?

附加信息:

  • 这两个应用程序均使用 Azure AD 进行保护
  • 登录后需要动态检索自定义声明并将其附加到令牌。

谢谢您的指导!

c# asp.net-mvc authentication azure-active-directory asp.net-core-webapi
1个回答
0
投票

我的想法是,当用户使用他们的微软帐户登录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; }
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.