【问题标题】:Implementing AbpIdentity cookies and JwtBearer实现 AbpIdentity cookie 和 JwtBearer
【发布时间】:2019-08-26 17:05:51
【问题描述】:

我继承了一个同时使用 Web API 和 MVC 前端的 ASPnetzero 应用程序。 API 通过 Bearer 进行身份验证,前端通过 AbpIdentity (Cookies) 进行身份验证。几天前,我勇敢地决定更新我的 nuGet 包。该更新伴随着从 .netCore v1 到 v2 的升级。但是在 JwtBearer 中间件过时后,我在身份验证方面遇到了一些困难。我可以使用 cookie 进行身份验证,但不能使用 Bearer Tokens。

我几乎尝试了所有方法。使用多种身份验证方法意味着一次只能使用一种。

在 Startup.cs 我有以下(sn-ps):

public IServiceProvider ConfigureServices(IServiceCollection services)
        {
            services.AddAbpIdentity<Tenant, User, Role>()
            .AddUserManager<UserManager>()
            .AddRoleManager<RoleManager>()
            .AddSignInManager<SignInManager>()
            .AddClaimsPrincipalFactory<UserClaimsPrincipalFactory>()
            .AddDefaultTokenProviders();
        }
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
        {
          AuthConfigurer.Configure(app, _appConfiguration);
         }

然而,这是一个自我回答的问题,我希望我能帮助任何有类似或相同情况的人,因为我已经制定了自己的解决方案。这个想法是让应用程序使用 Bearer 令牌(仅在使用 API 时)和 cookie(仅在使用 MVC 时)。

当 MVC 对 API 进行 XHR 调用以获取要在前端显示的数据时,我也遇到了挑战。这意味着 API 还需要使用 Cookie(但仅适用于 MVC 用户)。

【问题讨论】:

    标签: c# .net asp.net-core-2.0 aspnetboilerplate


    【解决方案1】:

    所以我终于想通了,它需要相当多的转变。结果是:

    1. API 用户仅使用 Bearer Token 进行身份验证
    2. MVC 用户使用 Cookie 进行身份验证,并且在登录后应用程序中的 API 调用使用相同的身份验证。

    所有更改都是在 Startup.cs 中进行的,我还注释掉了对 AuthConfigure.cs 文件的引用,该文件现已过时。我对解决方案的任何改进或建议持开放态度。

    Startup.cs 文件中的重要部分:

    public IServiceProvider ConfigureServices(IServiceCollection services)
            {
              services.AddAuthentication()
                    .AddJwtBearer(cfg =>
                    {
                        cfg.RequireHttpsMetadata = false;
                        cfg.SaveToken = true;
    
                        cfg.TokenValidationParameters = new TokenValidationParameters()
                        {
                            // The application URL is used for the Issuer and Audience and is included in the appsettings.json
                            ValidIssuer = _appConfiguration["Authentication:JwtBearer:Issuer"],
                            ValidAudience = _appConfiguration["Authentication:JwtBearer:Audience"],
                            IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_appConfiguration["Authentication:JwtBearer:SecurityKey"]))
                        };
    
                    });
    
                 // Activate Cookie Authentication without Identity, since Abp already implements Identity below.
                 services.ConfigureApplicationCookie(options => options.LoginPath = "/Account/Login");
    
                 // Add the Authentication Scheme Provider which will set the authentication method based on the kind of request. i.e API or MVC
                services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
                services.AddSingleton<IAuthenticationSchemeProvider, CustomAuthenticationSchemeProvider>();
    
                 // Some of these extensions changed
                 services.AddAbpIdentity<Tenant, User, Role>()
                .AddUserManager<UserManager>()
                .AddRoleManager<RoleManager>()
                .AddSignInManager<SignInManager>()
                .AddClaimsPrincipalFactory<UserClaimsPrincipalFactory>()
                .AddDefaultTokenProviders();
    //…
    }
    
    public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
            {
    // app.UseAuthentication is critical here
                app.UseAuthentication();
                app.UseAbp(); //Initializes ABP framework.
                app.UseCors("CorsPolicy");
    //…
     //AuthConfigurer.Configure(app, _appConfiguration);
    //…
             }
    }
    
    public class CustomAuthenticationSchemeProvider : AuthenticationSchemeProvider
    {
        private readonly IHttpContextAccessor httpContextAccessor;
    
        public CustomAuthenticationSchemeProvider(
            IHttpContextAccessor httpContextAccessor,
            IOptions<AuthenticationOptions> options)
            : base(options)
        {
            this.httpContextAccessor = httpContextAccessor;
        }
    
        private async Task<AuthenticationScheme> GetRequestSchemeAsync()
        {
            var request = httpContextAccessor.HttpContext?.Request;
            if (request == null)
            {
                throw new ArgumentNullException("The HTTP request cannot be retrieved.");
            }
    
            // For API requests, use authentication tokens.
    
            var authHeader = httpContextAccessor.HttpContext.Request.Headers["Authorization"].FirstOrDefault();
            if (authHeader?.StartsWith("Bearer ") == true)
            {
                return await GetSchemeAsync(JwtBearerDefaults.AuthenticationScheme);
            }
    
            // For the other requests, return null to let the base methods
            // decide what's the best scheme based on the default schemes
            // configured in the global authentication options.
            return null;
        }
    
        public override async Task<AuthenticationScheme> GetDefaultAuthenticateSchemeAsync() =>
            await GetRequestSchemeAsync() ??
            await base.GetDefaultAuthenticateSchemeAsync();
    
        public override async Task<AuthenticationScheme> GetDefaultChallengeSchemeAsync() =>
            await GetRequestSchemeAsync() ??
            await base.GetDefaultChallengeSchemeAsync();
    
        public override async Task<AuthenticationScheme> GetDefaultForbidSchemeAsync() =>
            await GetRequestSchemeAsync() ??
            await base.GetDefaultForbidSchemeAsync();
    
        public override async Task<AuthenticationScheme> GetDefaultSignInSchemeAsync() =>
            await GetRequestSchemeAsync() ??
            await base.GetDefaultSignInSchemeAsync();
    
        public override async Task<AuthenticationScheme> GetDefaultSignOutSchemeAsync() =>
            await GetRequestSchemeAsync() ??
            await base.GetDefaultSignOutSchemeAsync();
    }
    

    【讨论】:

    • 假设我有 JWT 身份验证 + AspNetCore 应用程序 + Angular 前端。当前令牌保存在本地存储中。突然,我想到了使用window.open 从Angular 应用程序调用某个页面的必要性。在这种情况下,只有 Cookie 或 URL 可用于读取用户身份。我不想通过 URL 发送我的令牌。所以我最终阅读了 Cookies。问题是:如何使用现有的 JWT 身份验证存储令牌到 Cookie?在哪里做呢? :) 而且 - 在这种情况下我需要放弃本地存储吗?
    猜你喜欢
    • 2018-02-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-23
    • 2023-03-15
    • 2012-07-10
    • 2014-01-10
    相关资源
    最近更新 更多