Добавление пользовательских значений в результат маршрута обмена токенами - PullRequest
0 голосов
/ 26 февраля 2019

В моем приложении .net core 2.2 MVC Web Api у меня есть конечная точка Token для моего клиентского приложения Angular.Я использую OpenIddictCore для аутентификации.Я не использую токены JWT, я использую непрозрачные токены по умолчанию с OpenIddict и хочу использовать роли и утверждения для защиты маршрутов в моем угловом приложении.Когда я запрашиваю токен из моей конечной точки Token в 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;
        }
    }

Если этот подход неверен, пожалуйста, сообщите мне.Я просто застрял.Пытаюсь реализовать это часами, и теперь я не чувствую свой мозг.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...