ASP.Net Core 2.1 IdentityCore (утверждения о ролях не добавляются при входе пользователя) - PullRequest
0 голосов
/ 07 октября 2018

Я использую ASP.Net Core 2.1 с IdentityCore Service , приложение представляет собой чистый API, никаких представлений вообще.Для аутентификации я просто использую Steam аутентификацию (Нет входа пользователя / пароля), предоставленную, https://github.com/aspnet-contrib/AspNet.Security.OpenId.Providers

Этот API был создан для соответствия очень специфическому рабочему процессу аутентификации (пользователь может тольковойдите в API через Steam) Angular SPA в качестве внешнего интерфейса отлично справляется с рабочим процессом.

Проблема в том, что когда я добавляю роль пользователю (у меня уже естьроли пропущены, и я добавил свою собственную учетную запись Steam в роль администратора), утверждения типа роли не добавляются при входе в систему, поэтому, когда пользователь администратора пытается получить доступ к маршруту API, защищенному [Authorize (Roles = "Admin")Мне возвращают Несанкционированное перенаправление.

Ниже я добавил все фрагменты кода, которые я считаю необходимыми (не стесняйтесь запрашивать больше).

Если я использую (в настоящее время я использую это каквременное решение, но оно не идеально для будущей разработки);

services.AddIdentity<User, Role>()
   .AddEntityFrameworkStores<RSContext>()
   .AddSignInManager<SignInManager<User>>()
   .AddRoleManager<RoleManager<Role>>()
   .AddDefaultTokenProviders();

Приложение правильно добавляет заявки на роль при входе пользователя (и атрибуты Authorize work), используя весь существующий код из AuthController.cs, но используя IdentityCore, он не работает.Я чувствую, что мне не хватает одной строки, которая отвечает за это, но после просмотра документов MSDN в течение нескольких дней я, наконец, перехитрил.

ПРИМЕЧАНИЕ: API правильно аутентифицирует и установить cookie-файлы пользователей при входе в систему, но не добавляет роли пользователей к заявкам пользователей.Поэтому аутентификация работает, авторизация - нет.Если я использую атрибут [Authorize] без указания роли, он работает безупречно и позволяет только аутентифицированным пользователям получать доступ к маршруту, в то же время отказывая неаутентифицированным пользователям.Это можно увидеть на скриншоте тестирования в конце: identity [0] .isAuthenticated = True, но роль администратора не добавляется в утверждения Identity.Как отмечалось выше, если я не использую AddIdentityCore и использую AddIdentity, роли будут правильно добавлены в утверждения пользователя, и атрибут [Authorize (Role = "Admin")] будет работать, как и ожидалось, только пользователи, не входящие в состав Adminроль для доступа к нему.

Startup.cs (пропущены нерелевантные части, например, соединение с базой данных)

public void ConfigureServices(IServiceCollection services)
{
    IdentityBuilder builder = services.AddIdentityCore<User>(opt =>
    {
        opt.Password.RequireDigit = true;
        opt.Password.RequiredLength = 6;
        opt.Password.RequireNonAlphanumeric = true;
        opt.Password.RequireUppercase = true;
        opt.User.AllowedUserNameCharacters += ":/";
    });

    builder = new IdentityBuilder(builder.UserType, typeof(Role), builder.Services);
    builder.AddEntityFrameworkStores<RSContext>();
    builder.AddSignInManager<SignInManager<User>>();
    builder.AddRoleValidator<RoleValidator<Role>>();
    builder.AddRoles<Role>();
    builder.AddRoleManager<RoleManager<Role>>();
    builder.AddClaimsPrincipalFactory<UserClaimsPrincipalFactory<User>>();
    builder.AddDefaultTokenProviders();

    services.AddAuthentication(options =>
    {
        options.DefaultScheme = IdentityConstants.ApplicationScheme;
        options.DefaultChallengeScheme = IdentityConstants.ApplicationScheme;
        options.DefaultAuthenticateScheme = IdentityConstants.ApplicationScheme;
        options.DefaultSignInScheme = IdentityConstants.ApplicationScheme;
        options.DefaultSignOutScheme = IdentityConstants.ApplicationScheme;
        options.DefaultForbidScheme = IdentityConstants.ApplicationScheme;
    })
        .AddSteam(options =>
        {
            options.ApplicationKey = Configuration.GetSection("Authentication:Steam:Key").Value;
            options.CallbackPath = "/api/auth/steam/callback";
            options.Events.OnAuthenticated = OnClientAuthenticated;
        })
        .AddIdentityCookies(options =>
        {
            options.ApplicationCookie.Configure(appCookie =>
            {
                appCookie.Cookie.Name = "RaidSimulator";
                appCookie.LoginPath = "/api/auth/login";
                appCookie.LogoutPath = "/api/auth/logout";
                appCookie.Cookie.HttpOnly = true;
                appCookie.Cookie.SameSite = SameSiteMode.Lax;
                appCookie.Cookie.IsEssential = true;
                appCookie.SlidingExpiration = true;
                appCookie.Cookie.Expiration = TimeSpan.FromMinutes(1);
                appCookie.Cookie.MaxAge = TimeSpan.FromDays(7);
            });
            options.ExternalCookie.Configure(extCookie =>
            {
                extCookie.Cookie.Name = "ExternalLogin";
                extCookie.LoginPath = "/api/auth/login";
                extCookie.LogoutPath = "/api/auth/logout";
                extCookie.Cookie.HttpOnly = true;
                extCookie.Cookie.SameSite = SameSiteMode.Lax;
                extCookie.Cookie.IsEssential = true;
                extCookie.Cookie.Expiration = TimeSpan.FromMinutes(10);
            });
        });
}

public void Configure(IApplicationBuilder app, IHostingEnvironment env, RoleManager<Role> roleManager)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }

    RolesSeed.Seed(roleManager).Wait();

    app.UseCors();
    app.UseAuthentication();
    app.UseMvc();
}

// Responsible for storing/updating steam profile in database
private async Task OnClientAuthenticated(OpenIdAuthenticatedContext context)
{
    var rsContext = context.HttpContext.RequestServices.GetRequiredService<RSContext>();
    var userManager = context.HttpContext.RequestServices.GetRequiredService<UserManager<User>>();

    var profile = context.User?.Value<JObject>(SteamAuthenticationConstants.Parameters.Response)
                        ?.Value<JArray>(SteamAuthenticationConstants.Parameters.Players)?[0]?.ToObject<SteamProfile>();

    // TODO: Handle this better, Redir user to an informative error page or something
    if (profile == null)
        return;

    var dbProfile = await rsContext.SteamProfiles.FindAsync(profile.SteamId);
    if (dbProfile != null)
    {
        rsContext.Update(dbProfile);
        dbProfile.UpdateProfile(profile);
        await rsContext.SaveChangesAsync();
    }
    else
    {
        await rsContext.SteamProfiles.AddAsync(profile);
        await rsContext.SaveChangesAsync();
    }
}

AuthController.cs => Единственный код, отвечающий за аутентификацию по схеме Identity.Application.

[HttpGet("callback")]
[Authorize(AuthenticationSchemes = "Steam")]
public async Task<IActionResult> Callback([FromQuery]string ReturnUrl)
{
    ReturnUrl = ReturnUrl?.Contains("api/") == true ? "/" : ReturnUrl;

    if (HttpContext.User.Claims.Count() > 0)
    {
        var provider = HttpContext.User.Identity.AuthenticationType;
        var nameIdentifier = HttpContext.User.FindFirstValue(ClaimTypes.NameIdentifier);
        var name = HttpContext.User.FindFirstValue(ClaimTypes.Name);

        var loginResult = await signInManager.ExternalLoginSignInAsync(provider, nameIdentifier, false);
        if (loginResult.Succeeded)
        {
            return Redirect(ReturnUrl ?? "/api/auth/claims");
        }

        var result = await userManager.CreateAsync(new User { UserName = nameIdentifier, SteamId = nameIdentifier.Split("/").Last() });
        if (result.Succeeded)
        {
            var user = await userManager.FindByNameAsync(nameIdentifier);
            var identity = await userManager.AddLoginAsync(user, new UserLoginInfo(provider, nameIdentifier, name));

            if (identity.Succeeded)
            {
                await signInManager.ExternalLoginSignInAsync(provider, nameIdentifier, false);
                return Redirect(ReturnUrl ?? "/api/auth/claims");
            }
        }
    }

    return BadRequest(new { success = false });
}

[HttpGet("claims")]
[Authorize]
public async Task<IActionResult> GetClaims()
{
    var user = await userManager.GetUserAsync(User);
    var claims =
        User.Claims.Select(c => new
        {
            c.Type,
            c.Value
        });

    var inAdmin = new string[] {
        "User.IsInRole(\"Admin\") = " + User.IsInRole("Admin"),
        "User.IsInRole(\"ADMIN\") = " + User.IsInRole("ADMIN"),
        "User.IsInRole(\"admin\") = " + User.IsInRole("admin"),
        "userManager.IsInRoleAsync(user, \"admin\") = " + await userManager.IsInRoleAsync(user, "admin")
    };

    return Ok(new { success = true, data = new { claims, inAdmin, User.Identities } });
}

RoleSeeder.cs

public static async Task Seed(RoleManager<Role> roleManager)
{
    // Developer Role
    if(!await roleManager.RoleExistsAsync("Developer"))
    {
        var role = new Role("Developer");
        await roleManager.CreateAsync(role);
    }
    // Community Manager Role
    if (!await roleManager.RoleExistsAsync("Community Manager"))
    {
        var role = new Role("Community Manager");
        await roleManager.CreateAsync(role);
    }
    // Admin Role
    if (!await roleManager.RoleExistsAsync("Admin"))
    {
        var role = new Role("Admin");
        await roleManager.CreateAsync(role);
    }
    // Moderator Role
    if (!await roleManager.RoleExistsAsync("Moderator"))
    {
        var role = new Role("Moderator");
        await roleManager.CreateAsync(role);
    }
}

Снимок экрана тестирования: Заявка / удостоверение личности / роль в тесте API Ответ

Ответы [ 2 ]

0 голосов
/ 08 октября 2018

Опубликовал эту проблему в репозитории ASP.Net Identity GitHub, это известная ошибка, которая была устранена в ASP.Net Core 2.2

Ссылка: https://github.com/aspnet/Identity/issues/1997

0 голосов
/ 07 октября 2018

У вас есть способ для этой проблемы.

При отправке запроса на любой WebService, если вы установите, Authorization будет запущено сейчас:

  1. До login Если вы хотите отправить запрос на WebService и хотите игнорировать Authorization, вам необходимо использовать Allowanonymus Атрибут, например:

    [Allowanonymous] Public void Login (){// здесь}

С этим атрибутом Авторизация будет игнорировать запрос.

сейчас!Если вы хотите отправить запрос после login, вам нужно создать cookie во время входа в систему и отправить ответ на client, а также сохранить этот файл cookie в вашем localStorage в клиенте для идентификации.в клиенте.После этого вы должны установить cookie в header каждого запроса.Таким образом, ваша авторизация будет Don!

Сейчас. Если вы хотите, я могу создать образец для авторизации в наилучшей практике.

...