asp.net-core - 使用 JWT 访问令牌的安全 API
问题描述
我正在使用 openiddict 授权代码流示例,一切运行良好。
https://github.com/openiddict/openiddict-samples/tree/dev/samples/CodeFlow
但是,我想做一些改变,我正在努力做到这一点。我想配置为使用 JWT 令牌而不是默认的不透明令牌,并且还分为授权服务器和资源服务器。我还有一个 MCV Web 应用程序,它将通过httpClient
.
验证服务器.启动
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.AddDbContext<ApplicationDbContext>(options =>
{
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"));
options.UseOpenIddict();
});
// Register the Identity services.
services.AddIdentity<ApplicationUser, IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
services.Configure<IdentityOptions>(options =>
{
options.ClaimsIdentity.UserNameClaimType = OpenIdConnectConstants.Claims.Name;
options.ClaimsIdentity.UserIdClaimType = OpenIdConnectConstants.Claims.Subject;
options.ClaimsIdentity.RoleClaimType = OpenIdConnectConstants.Claims.Role;
});
services.AddOpenIddict()
.AddCore(options =>
options.UseEntityFrameworkCore()
.UseDbContext<ApplicationDbContext>();
})
// Register the OpenIddict server handler.
.AddServer(options =>
{
options.UseMvc();
options.EnableAuthorizationEndpoint("/connect/authorize")
.EnableLogoutEndpoint("/connect/logout")
.EnableTokenEndpoint("/connect/token")
.EnableUserinfoEndpoint("/api/userinfo");
options.RegisterScopes(OpenIdConnectConstants.Scopes.Email,
OpenIdConnectConstants.Scopes.Profile,
OpenIddictConstants.Scopes.Roles);
options.AllowAuthorizationCodeFlow();
options.EnableRequestCaching();
options.DisableHttpsRequirement();
options.UseJsonWebTokens();
options.AddEphemeralSigningKey();
});
}
由于这不再是资源服务器,因此我删除了验证部分,因为我认为这不是必需的。因为我想使用 JWT,所以我取消了以下几行的注释:
options.UseJsonWebTokens();
options.AddEphemeralSigningKey();
授权端点返回与示例完全相同的登录结果,该结果重定向到 MVC 应用程序,然后该应用程序发出身份验证 cookie。我现在可以在我的 MVC APP 上访问受保护的资源。
MVC APP启动
public void ConfigureServices(IServiceCollection services)
{
services.Configure<PortalDetails>(options => Configuration.GetSection("PortalDetails").Bind(options));
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
JwtSecurityTokenHandler.DefaultOutboundClaimTypeMap.Clear();
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme).AddCookie(opts =>
{
opts.LoginPath = "/login";
opts.LogoutPath = "/logout";
})
.AddJwtBearer(options =>
{
//Authority must be a url. It does not have a default value.
options.Authority = "http://localhost:54540/";
options.Audience = "mvc"; //This must be included in ticket creation
options.RequireHttpsMetadata = false;
options.IncludeErrorDetails = true; //
options.TokenValidationParameters = new TokenValidationParameters()
{
NameClaimType = "sub",
RoleClaimType = "role"
};
})
.AddOpenIdConnect(options =>
{
// Note: these settings must match the application details
// inserted in the database at the server level.
options.ClientId = "mvc";
options.ClientSecret = "901564A5-E7FE-42CB-B10D-61EF6A8F3654";
options.RequireHttpsMetadata = false;
options.GetClaimsFromUserInfoEndpoint = false; // TODO: If this if true then it doesnt work??
options.SaveTokens = true;
// Use the authorization code flow.
options.ResponseType = OpenIdConnectResponseType.Code;
options.AuthenticationMethod = OpenIdConnectRedirectBehavior.RedirectGet;
// Note: setting the Authority allows the OIDC client middleware to automatically
// retrieve the identity provider's configuration and spare you from setting
// the different endpoints URIs or the token validation parameters explicitly.
options.Authority = "http://localhost:54540/";
options.Scope.Add("email");
options.Scope.Add("roles");
options.SecurityTokenValidator = new JwtSecurityTokenHandler
{
// Disable the built-in JWT claims mapping feature.,
InboundClaimTypeMap = new Dictionary<string, string>()
};
options.TokenValidationParameters.NameClaimType = "name";
options.TokenValidationParameters.RoleClaimType = "role";
});
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
services.AddHttpClient<IApiGatewayClient, ApiGatewayClient>();
services.AddSingleton<ITokenProvider, TokenProvider>();
}
调用我使用的资源服务器时:
string accessToken = await HttpContext.GetTokenAsync("access_token");
我可以看到一个访问令牌,我将它附加到我的 http 请求中:
_httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
但结果是被禁止的。
最后,我有一个受保护的资源服务器:
资源.启动
public void ConfigureServices(IServiceCollection services)
{
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
JwtSecurityTokenHandler.DefaultOutboundClaimTypeMap.Clear();
//Add authentication and set default authentication scheme
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) //same as "Bearer"
.AddJwtBearer(options =>
{
//Authority must be a url. It does not have a default value.
options.Authority = "http://localhost:54540";
options.Audience = "mvc"; //This must be included in ticket creation
options.RequireHttpsMetadata = false;
options.IncludeErrorDetails = true; //
options.TokenValidationParameters = new TokenValidationParameters()
{
NameClaimType = OpenIdConnectConstants.Claims.Subject,
RoleClaimType = OpenIdConnectConstants.Claims.Role,
};
});
services.AddMvc();
}
我想知道这是否是我的场景的正确设置,因为我从资源服务器获得了禁止的结果。
谢谢
解决方案
这是一个包
- 让在您的 Asp Net Core 2.0+ 应用程序中集成 JWT Bearer Token Security 变得轻而易举!
- Azure Active Directory 身份验证集成。
- Facebook 身份验证集成。
- Twitter 身份验证集成。
- 谷歌身份验证集成。
- 此外,Swagger UI 集成!
它被称为AspNetCore.Security.Jwt
GitHub:
https://github.com/VeritasSoftware/AspNetCore.Security.Jwt
该软件包将 JWT 不记名令牌集成到您的应用程序中,如下所示:
1.在你的应用中实现IAuthentication接口
using AspNetCore.Security.Jwt;
using System.Threading.Tasks;
namespace XXX.API
{
public class Authenticator : IAuthentication
{
public async Task<bool> IsValidUser(string id, string password)
{
//Put your id authenication here.
return true;
}
}
}
2. 在你的 Startup.cs
using AspNetCore.Security.Jwt;
using Swashbuckle.AspNetCore.Swagger;
.
.
public void ConfigureServices(IServiceCollection services)
{
.
.
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new Info { Title = "XXX API", Version = "v1" });
});
services.AddSecurity<Authenticator>(this.Configuration, true);
services.AddMvc().AddSecurity();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
.
.
.
// Enable middleware to serve swagger-ui (HTML, JS, CSS, etc.),
// specifying the Swagger JSON endpoint.
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "XXX API V1");
});
app.UseSecurity(true);
app.UseMvc();
}
3. 在你的 appsettings.json
注意:- 您可以使用 Manage User Secrets 菜单(右键单击您的项目)将这些设置放入 Secret Manager。
{
"SecuritySettings": {
"Secret": "a secret that needs to be at least 16 characters long",
"Issuer": "your app",
"Audience": "the client of your app",
"IdType": "Name",
"TokenExpiryInHours" : 2
},
.
.
.
}
然后您将自动获得端点:
/令牌
当您调用这些端点并成功通过身份验证时,您将获得一个 JWT Bearer Token。
在您想要保护的控制器中
您必须使用 Authorize 属性标记要保护的控制器或操作,例如:
using Microsoft.AspNetCore.Mvc;
.
.
.
namespace XXX.API.Controllers
{
using Microsoft.AspNetCore.Authorization;
[Authorize]
[Route("api/[controller]")]
public class XXXController : Controller
{
.
.
.
}
}
在 Swagger UI 中,您将自动看到这些端点。
推荐阅读
- ios - Swift:如何以编程方式在 TableViewCell 中显示 CollectionView
- python - 如何在 django 中的子查询集上使用 order 子句过滤查询集
- flutter - 在等待初始化应用程序时显示进度指示器,例如在验证用户时
- python - 如何使用熊猫更改 csv 表?
- vue.js - 由于多人应用程序,Vus JS 更新文本区域一次
- python - 使用烧瓶在 HTML 文件中显示部分 python 字典
- ios - 嵌入在 UIStackView 中的 UITableView 不会重新加载数据
- c++ - 在快速排序中镜像字符串向量中整数向量的位置变化
- docker - Web 服务器重新启动后,Windows Server Docker 容器无法连接到代理容器
- roblox - 尝试使用一个 RemoteEvent 创建 TeamChanger