将自定义值添加到令牌交换路由结果中

时间:2019-02-25 23:51:30

标签: asp.net-identity asp.net-core-webapi openid-connect openiddict

在我的.net core 2.2 MVC Web Api应用程序中,我有一个Angular客户端应用程序的令牌终结点。我正在使用OpenIddictCore进行身份验证。我没有使用JWT令牌,而是将默认的不透明令牌与OpenIddict一起使用,我想使用角色和声明来保护我的角度应用程序上的路由。当我从Web Api的令牌端点请求令牌时,得到以下结果:

{
"token_type":"Bearer",
"access_token":"{access token here}",
"expires_in":3600
}

没有提供我有关角色的信息。是否有任何适当的方法来获得像这样的JSON响应:

{
"token_type":"Bearer",
"access_token":"{access token here}",
"expires_in":3600,
"roles":["ResourceEditor","ResourceViewer"... etc]
}

我已经搜索了很多,但是找不到任何东西。因为我一直在寻找解决方案。

一切正常,只要授权,一切都会正常。我的启动配置是:

services.AddDbContext<xxDbContext>(opt =>
    {
        opt.UseOpenIddict<Guid>();
        opt.UseSqlServer(
            @"Server=xxServer;Database=xxDB;User Id=xxUser;Password=xxPassword");
    });
services.Configure<IdentityOptions>(opt =>
    {
        opt.ClaimsIdentity.UserNameClaimType = OpenIdConnectConstants.Claims.Name;
        opt.ClaimsIdentity.UserIdClaimType = OpenIdConnectConstants.Claims.Subject;
        opt.ClaimsIdentity.RoleClaimType = OpenIdConnectConstants.Claims.Role;
        opt.Password.RequireDigit = true;
        opt.Password.RequiredLength = 8;
        opt.Password.RequireLowercase = true;
        opt.Password.RequireUppercase = true;
        opt.Password.RequireNonAlphanumeric = false;    
        //opt.SignIn.RequireConfirmedEmail = true;
    });

services.AddIdentity<UserEntity, UserRoleEntity>()
    .AddEntityFrameworkStores<xxDbContext>()
    .AddDefaultTokenProviders();

// Add OpenIddict services
services.AddOpenIddict(opt =>
    {
        opt.AddCore(conf => { conf.UseEntityFrameworkCore().UseDbContext<xxDbContext>(); });
        opt.AddServer(conf =>
        {
            conf.UseMvc();
            conf.EnableTokenEndpoint("/api/token");
            conf.AllowPasswordFlow();
            conf.AcceptAnonymousClients();
            conf.RegisterClaims(OpenIdConnectConstants.Claims.Role,OpenIdConnectConstants.Claims.Username);
            //conf.UseJsonWebTokens();
            //this doesn't works so I keep going with opaque tokens
            //conf.AddSigningCertificate(
            //    assembly: typeof(Startup).GetTypeInfo().Assembly,
            //    resource: "path to .pfx",
            //    password: "secret");
        });
        opt.AddValidation();
    });

services.AddAuthentication(options =>
    {
        options.DefaultScheme = OpenIddictValidationDefaults.AuthenticationScheme;
        options.DefaultAuthenticateScheme = OpenIddictValidationDefaults.AuthenticationScheme;
        options.DefaultChallengeScheme = OpenIddictValidationDefaults.AuthenticationScheme;
    });

我的令牌终结点是:

    [Route("api/[controller]")]
    public class TokenController : Controller
    {
        private readonly IOptions<IdentityOptions> _identityOptions;
        private readonly SignInManager<UserEntity> _signInManager;
        private readonly UserManager<UserEntity> _userManager;

        public TokenController(IOptions<IdentityOptions> identityOptions, SignInManager<UserEntity> signInManager,
            UserManager<UserEntity> userManager)
        {
            _identityOptions = identityOptions;
            _signInManager = signInManager;
            _userManager = userManager;
        }

        [HttpPost(Name = nameof(TokenExchangeAsync))]
        public async Task<IActionResult> TokenExchangeAsync(
            OpenIdConnectRequest request,
            CancellationToken ct)
        {
            if (!request.IsPasswordGrantType())
            {
                return BadRequest(new OpenIdConnectResponse()
                {
                    Error = OpenIdConnectConstants.Errors.UnsupportedGrantType,
                    ErrorDescription = "The specified grant type is not supported"
                });
            }

            var user = await _userManager.FindByNameAsync(request.Username);
            if (user == null)
                return BadRequest(new OpenIdConnectResponse()
                {
                    Error = OpenIdConnectConstants.Errors.InvalidGrant,
                    ErrorDescription = "The username or password is invalid"
                });


            if (!await _signInManager.CanSignInAsync(user))
                return BadRequest(new OpenIdConnectResponse()
                {
                    Error = OpenIdConnectConstants.Errors.InvalidGrant,
                    ErrorDescription = "The specified user is not allowed to sign in"
                });

            // Ensure the user is not already locked out
            if (_userManager.SupportsUserLockout && await _userManager.IsLockedOutAsync(user))
            {
                return BadRequest(new OpenIdConnectResponse
                {
                    Error = OpenIdConnectConstants.Errors.InvalidGrant,
                    ErrorDescription = "The username or password is invalid."
                });
            }


            if (!await _userManager.CheckPasswordAsync(user, request.Password))
            {
                if (_userManager.SupportsUserLockout)
                {
                    await _userManager.AccessFailedAsync(user);
                }

                return BadRequest(new OpenIdConnectResponse
                {
                    Error = OpenIdConnectConstants.Errors.InvalidGrant,
                    ErrorDescription = "The username or password is invalid."
                });
            }



            if (_userManager.SupportsUserLockout)
            {
                await _userManager.ResetAccessFailedCountAsync(user);
            }

            // Create a new authentication ticket w/ the user identity
            var ticket = await CreateTicketAsync(request, user);

            return SignIn(ticket.Principal, ticket.Properties, ticket.AuthenticationScheme);
        }

        private async Task<AuthenticationTicket> CreateTicketAsync(OpenIdConnectRequest request, UserEntity user)
        {
            var principal = await _signInManager.CreateUserPrincipalAsync(user);

            var ticket = new AuthenticationTicket(principal,
                new AuthenticationProperties(),
                OpenIdConnectServerDefaults.AuthenticationScheme);


            foreach (var claim in ticket.Principal.Claims)
            {

                if (claim.Type == _identityOptions.Value.ClaimsIdentity.SecurityStampClaimType) continue;

                claim.SetDestinations(OpenIdConnectConstants.Destinations.AccessToken);
            }

            return ticket;
        }
    }

如果此方法不正确,请告诉我。我只是被卡住了。试图实施此方法数小时,现在我无法感觉到我的大脑。

0 个答案:

没有答案