Implementing AbpIdentity cookies and JwtBearer



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

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

在启动中.cs我有以下内容(片段):

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);
}

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

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

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

  1. API 用户仅使用持有者令牌进行身份验证
  2. MVC 用户使用 Cookie 进行身份验证,并且在他们登录后,对应用程序中的 API 调用使用相同的身份验证。

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

启动.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();
}

最新更新