Проблемы с ролями и jwt токеном

При переходе на /admin пишет ошибку 401, однако вроде роли настроены, использую jwt токен

Мой код C#

using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Authentication.OAuth;
using Microsoft.AspNetCore.Authorization;
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;

var adminRole = new Role("admin");
var userRole = new Role("user");

var people = new List<Account>
{
    new Account("Lololoshka", "123", adminRole),
    new Account("Karal", "qwerty", userRole)
};

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddAuthorization();

//Конфигурация и валидация токена
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddJwtBearer(options =>
    {
        options.TokenValidationParameters = new TokenValidationParameters
        {
            // указывает, будет ли валидироваться издатель при валидации токена
            ValidateIssuer = true,
            // строка, представляющая издателя
            ValidIssuer = AuthOptions.ISSUER,
            // будет ли валидироваться потребитель токена
            ValidateAudience = true,
            // установка потребителя токена
            ValidAudience = AuthOptions.AUDIENCE,
            // будет ли валидироваться время существования
            ValidateLifetime = true,
            // установка ключа безопасности
            IssuerSigningKey = AuthOptions.GetSymmetricSecurityKey(),
            // валидация ключа безопасности
            ValidateIssuerSigningKey = true,
        };
    });


var app = builder.Build();

app.UseDefaultFiles();
app.UseStaticFiles();

app.UseAuthentication();
app.UseAuthorization();



//Генерация токена во время входа
//Генерация токена во время входа
app.MapPost("/login", (Account user) =>
{
    Account? person = people.FirstOrDefault(p => p.Login == user.Login && p.Password == user.Password);
    if (person is null) return Results.Unauthorized();

    var claims = new List<Claim>
    {
        new Claim(ClaimTypes.Name, person.Login),
        new Claim(ClaimTypes.Role, person.Role.Name)
        // добавьте другие необходимые заявки, если есть
    };

    var jwt = new JwtSecurityToken(
            issuer: AuthOptions.ISSUER,
            audience: AuthOptions.AUDIENCE,
            claims: claims,
            expires: DateTime.UtcNow.Add(TimeSpan.FromMinutes(2)),
            signingCredentials: new SigningCredentials(AuthOptions.GetSymmetricSecurityKey(), SecurityAlgorithms.HmacSha256));

    var encodedJwt = new JwtSecurityTokenHandler().WriteToken(jwt);

    // вывод информации о токене в консоль
    Console.WriteLine("Generated token: " + encodedJwt);

    var response = new
    {
        access_token = encodedJwt,
        username = person.Login
    };

    return Results.Json(response);
});






app.Map("/data", [Authorize] () => new { message = "Hello cats!" });
// доступ только для роли admin
app.Map("/admin", [Authorize(Roles = "admin")] () => new { message = "Admin!" });
app.Run();


//Настройки генерации токена
public class AuthOptions
{
    public const string ISSUER = "CatServer";
    public const string AUDIENCE = "CatClient";
    const string KEY = "ewiuGFPEGQRBIIWT4GIU[35QGSOdsfIHTwerFNHVDU43";
    public static SymmetricSecurityKey GetSymmetricSecurityKey()=>
        new SymmetricSecurityKey(Encoding.UTF8.GetBytes(KEY));
}

public class Account
{
    public string Login { get; set; }
    public string Password { get; set; }
    public Role Role { get; set; }

    public Account(string login, string password, Role role)
    {
        Login = login;
        Password = password;
        Role = role;
    }
}

public class Role
{
    public string Name { get; set; }
    public Role(string name) => Name = name;
}

Мой фронт

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>CAT.COM</title>
</head>
<body>
    <div id="userInfo" style="display:none;">
        <p>Добро пожаловать <span id="userName"></span>!</p>
        <input type="button" value="Выйти" id="logOut" />
        <p>
            <button id="adminPanel">Административная панель</button>
        </p>
    </div>
    <div id="loginForm">
        <h3>Вход на сайт</h3>
        <p>
            <label>Введите логин</label><br />
            <input type="email" id="email" />
        </p>
        <p>
            <label>Введите пароль</label><br />
            <input type="password" id="password" />
        </p>
        <input type="submit" id="submitLogin" value="Войти" />
    </div>
    <p>
        <input type="submit" id="getData" value="Получить данные" />
    </p>
    <script>
        var tokenKey = "accessToken";
        document.getElementById("submitLogin").addEventListener("click", async e => {
            e.preventDefault();
            const response = await fetch("/login", {
                method: "POST",
                headers: { "Accept": "application/json", "Content-Type": "application/json" },
                body: JSON.stringify({
                    Login: document.getElementById("email").value,
                    Password: document.getElementById("password").value
                })
            });
            if (response.ok === true) {
                const data = await response.json();
                document.getElementById("userName").innerText = data.username;
                document.getElementById("userInfo").style.display = "block";
                document.getElementById("loginForm").style.display = "none";
                sessionStorage.setItem(tokenKey, data.access_token);
            }
            else
                console.log("Status: ", response.status);
        });

        document.getElementById("getData").addEventListener("click", async e => {
            e.preventDefault();
            const token = sessionStorage.getItem(tokenKey);
            const response = await fetch("/data", {
                method: "GET",
                headers: {
                    "Accept": "application/json",
                    "Authorization": "Bearer " + token
                }
            });

            if (response.ok === true) {
                const data = await response.json();
                alert(data.message);
            }
            else
                console.log("Status: ", response.status);
        });

        document.getElementById("adminPanel").addEventListener("click", async e => {
            e.preventDefault();
            const token = sessionStorage.getItem(tokenKey);
            const response = await fetch("/admin", {
                method: "GET",
                headers: {
                    "Authorization": "Bearer " + token
                }
            });

            if (response.ok === true) {
                window.location.href = "/admin";
            } else {
                console.log("Status: ", response.status);
            }
        });

        document.getElementById("logOut").addEventListener("click", e => {
            e.preventDefault();
            document.getElementById("userName").innerText = "";
            document.getElementById("userInfo").style.display = "none";
            document.getElementById("loginForm").style.display = "block";
            sessionStorage.removeItem(tokenKey);
        });
    </script>
</body>
</html>


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

Автор решения: Alatyrev Danila Artemovich

Чтобы с ролями работать, нужно сначала их зарегистрировать в Identity:

var RoleManager = serviceProvider.GetRequiredService<RoleManager<IdentityRole>>();
var UserManager = serviceProvider.GetRequiredService<UserManager<Domain.Models.User>>();
string[] roleNames = { "Admin", "Manager", "Member" };

IdentityResult roleResult;
foreach (var roleName in roleNames)
{
    var roleExist = await RoleManager.RoleExistsAsync(roleName);
    if (!roleExist)
    {
        //create the roles and seed them to the database: Question 1
        roleResult = await RoleManager.CreateAsync(new IdentityRole(roleName));
    }
}
→ Ссылка