Как добавить роли в claims?

У меня в приложении asp.net core 2.2 реализована аутентификация по токенам (примерно как в этом ответе), теперь вот думаю, как мне передать в токен роли (штатные, из таблички dbo.AspNetRoles).

Поскольку я не особо разбираюсь в криптографии, то сижу пытаюсь понять, как это сделать правильно. Логично же, что в payload записывать нельзя, потому что можно будет подделать?

Вот мой текущий код:

public class AuthController : Controller
{
    private readonly UserManager<ApplicationUser> UserManager;
    private readonly SignInManager<ApplicationUser> SignInManager;

    public AuthController(UserManager<ApplicationUser> userManager, SignInManager<ApplicationUser> signInManager)
    {
        this.UserManager = userManager;
        this.SignInManager = signInManager;
    }

    [HttpPost("/api/token")]
    public async Task Token([FromBody] TokenRequest tokenRequest)
    {
        var principal = await this.GetIdentity(tokenRequest);

        if (principal == null)
        {
            this.Response.StatusCode = 400;
            await this.WriteResponse("Invalid username or password.");
            return;
        }

        var response = new
        {
            token = new TokenGenerator().Generate(DateTime.UtcNow, principal.Claims),
            username = principal.Identity.Name,
        };

        await this.WriteResponse(response);
    }

    private async Task WriteResponse(object response)
    {
        this.Response.ContentType = "application/json";
        await this.Response.WriteAsync(JsonConvert.SerializeObject(response, new JsonSerializerSettings { Formatting = Formatting.Indented }));
    }

    private async Task<ClaimsPrincipal> GetIdentity(TokenRequest tokenRequest)
    {
        var user = this.UserManager.Users.FirstOrDefault(x => x.NormalizedEmail == tokenRequest.UserName);
        if (user != null)
        {
            var check = await this.UserManager.CheckPasswordAsync(user, tokenRequest.Password);
            if (check)
            {
                var principal = await this.SignInManager.CreateUserPrincipalAsync(user);
                return principal;
            }
        }
        return null;
    }

    public class TokenRequest
    {
        public string UserName { get; set; }
        public string Password { get; set; }
    }
}

и генерация токена:

public class TokenGenerator
{
    public string Generate(DateTime now, IEnumerable<Claim> claims)
    {
        var token = Emit(now, claims);
        var encoded = Encode(token);
        return encoded;
    }

    private static JwtSecurityToken Emit(DateTime now, IEnumerable<Claim> claims)
    {
        return new JwtSecurityToken(
            AuthOptions.ISSUER,
            AuthOptions.AUDIENCE,
            claims,
            now,
            now.Add(TimeSpan.FromHours(AuthOptions.LIFETIME)),
            new SigningCredentials(AuthOptions.GetSymmetricSecurityKey(), SecurityAlgorithms.HmacSha256));
    }

    private static string Encode(JwtSecurityToken token)
    {
        return new JwtSecurityTokenHandler().WriteToken(token);
    }
}

Ответы (1 шт):

Автор решения: A K

Странно, но похоже что это всё вообще реализуется автоматически где-то в недрах identity фреймворка.

Решил ещё раз глянуть что там в claims бегает, поэкспериментировал немного.

Вот чистый пользователь без ролей:

введите сюда описание изображения

Вот пользователь с одной ролью:

введите сюда описание изображения

И вот он же, ещё одну роль навесил:

введите сюда описание изображения

Ну и соответственно, работает штатный атрибут Authorize:

    [HttpPost]
    [Authorize(Roles = "admin")]
    public async Task<object> Create(Persons.Create.PersonData request, CancellationToken cancellationToken)
    {
        var command = new Persons.Create.Command(request, this.User);
        var result  = await this.Mediator.Send(command, cancellationToken);
        return result;
    }

При этом если смотреть sql profiler - видно, что да, при логине идёт как раз запрос к таблицам с ролями.

→ Ссылка