简体   繁体   中英

How to pass created user claims to client

I have created multiple claims that sit in the AspNetUserClaims table for identity and have assigned them to my user id.

I am currently trying to get these to pull through in the list of claims I receive in my client application.

I have managed to pull through all the roles from the AspNetUserRoles table by adding the 'roles' scope to my client identity settings and then also in identity configuration (using the EF database format aka ConfigurationDbContext) created a record in the IdentityResources table which links to an identity claim called 'role'.

This is working as expected. However, I am not getting any of my UserClaims I have created through, do I need to create another specific scope?

Here is my client configuration:

services.AddAuthentication(options =>
    {
        options.DefaultScheme = "cookie";
        options.DefaultChallengeScheme = "oidc";
    })
    .AddCookie("cookie")
    .AddOpenIdConnect("oidc", options =>
    {
        options.Authority = "https://localhost:44335/";
        options.ClientId = "openIdConnectClient";
        options.SignInScheme = "cookie";
        options.ResponseType = "id_token";
        options.GetClaimsFromUserInfoEndpoint = true;
        options.Scope.Add("openid profile roles all_claims");
    });

services.AddAuthorization();

this is how I'm checking what claims the user has:

var claims = ((ClaimsIdentity)User.Identity).Claims;

and it returns all roles and profile claims (eg preferred_username) just not those specified within the AspNetUserClaims table.

For my client I have also set the property [AlwaysIncludeUserClaimsInIdToken] to true with no luck.

Does anyone know what I'm missing to pass through the user claims?

you can get the user claims like this:

var claims = User.Claims.Select(c => new { c.Type, c.Value });

you can implement this as an endpoint in your api which you stated as scope in your identity server:

using IdentityServer4;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using System.Linq;

namespace IdentityServer4Demo.Api
{
    [Route("/api/test")]
    [Authorize]
    public class TestController : ControllerBase
    {
        public IActionResult Get()
        {
            var claims = User.Claims.Select(c => new { c.Type, c.Value });
            return new JsonResult(claims);
        }
    }
}

If you want to add more claim you need to add property to the class which implements IdentityUser and use it in your custom profile service

using Microsoft.AspNetCore.Identity;

namespace AuthServer.Infrastructure.Data.Identity
{
    public class AppUser : IdentityUser
    {
        // Add additional profile data for application users by adding properties to this class
        public string Name { get; set; }        
    }
}

your custom profile service:

using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
using AuthServer.Infrastructure.Constants;
using AuthServer.Infrastructure.Data.Identity;
using IdentityModel;
using IdentityServer4;
using IdentityServer4.Extensions;
using IdentityServer4.Models;
using IdentityServer4.Services;
using Microsoft.AspNetCore.Identity;

namespace AuthServer.Infrastructure.Services
{
    public class IdentityClaimsProfileService : IProfileService
    {
        private readonly IUserClaimsPrincipalFactory<AppUser> _claimsFactory;
        private readonly UserManager<AppUser> _userManager;

        public IdentityClaimsProfileService(UserManager<AppUser> userManager, IUserClaimsPrincipalFactory<AppUser> claimsFactory)
        {
            _userManager = userManager;
            _claimsFactory = claimsFactory;
        }

        public async Task GetProfileDataAsync(ProfileDataRequestContext context)
        {
            var sub = context.Subject.GetSubjectId();
            var user = await _userManager.FindByIdAsync(sub);
            var principal = await _claimsFactory.CreateAsync(user);

            var claims = principal.Claims.ToList();
            claims = claims.Where(claim => context.RequestedClaimTypes.Contains(claim.Type)).ToList();
            claims.Add(new Claim(JwtClaimTypes.GivenName, user.Name));
            claims.Add(new Claim(IdentityServerConstants.StandardScopes.Email, user.Email));
            // note: to dynamically add roles (ie. for users other than consumers - simply look them up by sub id
            claims.Add(new Claim(ClaimTypes.Role, Roles.Consumer)); // need this for role-based authorization - https://stackoverflow.com/questions/40844310/role-based-authorization-with-identityserver4

            context.IssuedClaims = claims;
        }
}

Do you have a IProfileService implementation to populate your custom claims?

You should implemet IProfileService as indicated in this answer .

Try other response_type than id_token since your application does not have an access token to call User Info endpoint. Maybe with id_token token to maintain the implicit flow grant of your client.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM