使用身份服务器3.0和oAuth 2.0时,如何在多个应用程序(Web/Mobile)之间共享JWT令牌



我们有一个基于Identity server 3.0构建的安全令牌服务器,用于管理多个应用程序(包括单页和本地移动应用程序)的安全性。还有资源服务器(一个RESTful API,需要由上述应用程序访问)。移动应用程序提供了客户端信息的摘要视图,用户需要导航到单页应用程序以获得客户端的完整视图。

目前,移动应用程序(Cordova)通过资源所有者客户端凭据授予从资源服务器检索客户端信息摘要,并在Cordova应用程序中以网格的形式显示客户端信息列表。

现在的要求是在单页应用程序(AngularJS)中打开客户端详细信息(详细信息视图),而无需用户再次登录。此时,移动应用程序拥有一个可以访问资源服务器(作用域)的令牌。

现在的问题是如何将我们拥有的令牌传递给单页应用程序(AngularJS),而不在URL中发送它(令牌)。请一些人谈谈处理这种情况的最佳方式是什么?

确保所有平台共享相同的"秘密">

您需要的是两个应用程序之间的单一登录(SSO)行为。但您使用的当前流量存在问题。

由于您当前使用的是Resource Owner Client Credential Grant,因此您没有使用身份服务器的最终用户登录。相反,我认为您可以从移动应用程序中获取最终用户凭据,并调用令牌端点来获取令牌。

从OAuth/OpenIDConnect的角度来看,SSO是在浏览器cookie之上实现的。它是如何工作的?

1. App A follow a flow that utilize front channel login (ex:-
Authorization code flow with PKCE)
2. End user is present with login page of Identity Server
3. App A completes the flow and obtain tokens
4. App B use a flow utilize front channel login
4. Identity server get login request and see cookies which correlate previously logged in user
5. Because of cookies, log in page is skipped and optionally consent page will be  showed
6. App B completes the flow and obtain tokens

这就是SSO的工作方式,正如您所看到的,它需要浏览器的参与。我认为这是解决这个问题的正确方法。

此外,不鼓励客户端从OAuth/OpenIDConnect主体获取最终用户凭据。如果应用程序具有特权或不能使用浏览器参与(来源),那么您的客户端流是可以的。

ASP.NET Core 3.1和JWT令牌

当第一个API具有身份验证逻辑时,您可以对第二个API使用相同的配置。认证后,您可以通过HTTPHeader(Authorize)发送JWT令牌,这可以被第二个API理解,因为它具有相同的配置/密钥值。

Appsettings.json:

"Jwt": {
"Key": "IamThePrivateKey",
"Issuer": "ImTheIssuer",
"Audience": "ImTheAudience"
},

在API查找令牌的任何位置都可以使用相同的配置,这不需要重新验证

启动.cs

public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddMvc();
services.AddSwaggerGen(option =>
{
option.SwaggerDoc("v1", new OpenApiInfo()
{
Title = "My API ",
Version = "v1",
Description = "My RESTful API"
});

option.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
{
Description = "My API Authorization",
Name = "Authorization",
In = ParameterLocation.Header,
Type = SecuritySchemeType.ApiKey,
Scheme = "bearer"
});
option.AddSecurityRequirement(new OpenApiSecurityRequirement
{
{
new OpenApiSecurityScheme
{
Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "Bearer" }
},
new List<string>()
}
});
} );
services.AddAuthentication(option =>
{
option.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
option.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(option =>
{
option.SaveToken = true;
option.TokenValidationParameters = new TokenValidationParameters
{
SaveSigninToken = true,
ValidateIssuer = true,
ValidateAudience = false,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = Configuration["Jwt:Issuer"], //from Appsettings.json
ValidAudience = Configuration["Jwt:Issuer"], //from Appsettings.json
IssuerSigningKey = new SymmetricSecurityKey(System.Text.Encoding.UTF8.GetBytes(Configuration["Jwt:Key"])) 
//from Appsettings.json
};
});
var container = new ContainerBuilder();
container.Populate(services);
//new AutofacServiceProvider(container.Build());            
}

最新更新