在客户端向委托人添加自定义声明(用于授权)

时间:2020-03-03 19:16:06

标签: .net-core identityserver4 asp.net-core-3.1

我已经能够在.net core 3.1上成功实现自己的IdentityServer4身份验证服务器,并且有一个客户端Web应用程序与其连接。客户端已成功接收访问令牌和ID。令牌包含所有用户标识信息。

我的下一个目标是将用户在客户端中具有的特权添加到HttpContext.User中,作为权利要求,在我获得令牌之后立即呈现任何其他页面。特权通过subjectId存储在与用户关联的数据库中。

我需要在哪里可以添加这些声明的帮助,以便我的授权策略可以与主体中的声明配合使用。我希望每次发行令牌时都执行该过程。

P.S。我正在使用GetClaimsFromUserInfoEndpoint = true和SaveTokens = true的身份服务器代码流。

谢谢!

2 个答案:

答案 0 :(得分:1)

您可以在identityServer4中使用Profile sevise:

 services .AddIdentityServer(x =>
            {
                x.IssuerUri = "null";
                x.Authentication.CookieLifetime = TimeSpan.FromDays(10);
            })
.
.
.          
              .AddProfileService<ProfileService>();

这是一个很好的参考:http://docs.identityserver.io/en/latest/reference/profileservice.html 而且ProfileService可以像这样的代码模板:

public class ProfileService : IProfileService
{
    private readonly UserManager<ApplicationUser> _userManager;


    public ProfileService(UserManager<ApplicationUser> userManager)
    {
        _userManager = userManager;

    }

    public async Task GetProfileDataAsync(ProfileDataRequestContext context)
    {
        var subject = context.Subject ?? throw new ArgumentNullException(nameof(context.Subject));

        var subjectId = subject.Claims.Where(x => x.Type == "sub").FirstOrDefault().Value;

        var user = await _userManager.FindByIdAsync(subjectId);
        if (user == null)
            throw new ArgumentException("Invalid subject identifier");

        var claims = GetClaimsFromUser(user,subject);
        context.IssuedClaims = claims.Result.ToList();
    }

    public async Task IsActiveAsync(IsActiveContext context)
    {
        var subject = context.Subject ?? throw new ArgumentNullException(nameof(context.Subject));

        var subjectId = subject.Claims.Where(x => x.Type == "sub").FirstOrDefault().Value;
        var user = await _userManager.FindByIdAsync(subjectId);

        context.IsActive = false;

        if (user != null)
        {
            if (_userManager.SupportsUserSecurityStamp)
            {
                var security_stamp = subject.Claims.Where(c => c.Type == "security_stamp").Select(c => c.Value).SingleOrDefault();
                if (security_stamp != null)
                {
                    var db_security_stamp = await _userManager.GetSecurityStampAsync(user);
                    if (db_security_stamp != security_stamp)
                        return;
                }
            }

            context.IsActive =
                !user.LockoutEnabled ||
                !user.LockoutEnd.HasValue ||
                user.LockoutEnd <= DateTime.Now;
        }
    }

    private async Task<IEnumerable<Claim>> GetClaimsFromUser(ApplicationUser user,ClaimsPrincipal subject)
    {
        var claims = new List<Claim>
        {
            new Claim(JwtClaimTypes.Subject, user.Id),
            new Claim(JwtClaimTypes.PreferredUserName, user.UserName),
            new Claim(JwtRegisteredClaimNames.UniqueName, user.UserName)

        };

        if (!string.IsNullOrWhiteSpace(user.Name))
            claims.Add(new Claim("name", user.Name));

        if (!string.IsNullOrWhiteSpace(user.LastName))
            claims.Add(new Claim("last_name", user.LastName));


        return claims;
    }
}

答案 1 :(得分:0)

您可以通过使用TokenValidated事件来实现

    public class CustomJwtBearerEvents : JwtBearerEvents
{
    public override async Task TokenValidated(TokenValidatedContext context)
    {
        var claims = context.Principal.Claims.ToList();
        claims.Add(new Claim("key", "value"));
        context.Principal = new ClaimsPrincipal(new ClaimsIdentity(claims, "Bearer"));        }
}

然后在启动时注册

        services.AddAuthentication(options =>
            {
                options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
            })
            .AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, options =>
            {
              ...
                options.Events = new JwtBearerEvents();
                options.EventsType = typeof(CustomJwtBearerEvents);
            });