Asp.Net Core 之 IdentityServer4
1、什么是IdentityServer4
IdentityServer4是依赖于asp.net core 6.0来实现openId和oauth2.0协议的身份认证框架。
用户(User):用户是使用已注册的客户端(指在id4中已经注册)访问资源的人。
客户端(Client):客户端就是从identityserver请求令牌的软件(你可以理解为一个app即可),既可以通过身份认证令牌来验证识别用户身份,又可以通过授权令牌来访问服务端的资源。但是客户端首先必须在申请令牌前已经在identityserver服务中注册过。
实际客户端不仅可以是Web应用程序,app或桌面应用程序(你就理解为pc端的软件即可),SPA,服务器进程等。
资源(Resources):
资源就是你想用identityserver保护的东东,可以是用户的身份数据或者api资源。
每一个资源都有一个唯一的名称,客户端使用这个唯一的名称来确定想访问哪一个资源(在访问之前,实际identityserver服务端已经配置好了哪个客户端可以访问哪个资源,所以你不必理解为客户端只要指定名称他们就可以随便访问任何一个资源)。
用户的身份信息实际由一组claim组成,例如姓名或者邮件都会包含在身份信息中(将来通过identityserver校验后都会返回给被调用的客户端)。
API资源就是客户端想要调用的功能(通常以json或xml的格式返回给客户端,例如webapi,wcf,webservice),通常通过webapi来建立模型,但是不一定是webapi,我刚才已经强调可以使其他类型的格式,这个要看具体的使用场景了。
身份令牌(顾名思义用于做身份认证,例如sso其实主要就是用于身份认证):id_token jwt
一个身份令牌指的就是对认证过程的描述。它至少要标识某个用户(Called the sub aka subject claim)的主身份信息,和该用户的认证时间和认证方式。但是身份令牌可以包含额外的身份数据,具体开发者可以自行设定,但是一般情况为了确保数据传输的效率,开发者一般不做过多额外的设置,大家也可以根据使用场景自行决定。
访问令牌(用于做客户端访问授权): access_token oauth 2.0
访问令牌允许客户端访问某个 API 资源。客户端请求到访问令牌,然后使用这个令牌来访问 API资源。访问令牌包含了客户端和用户(如果有的话,这取决于业务是否需要,但通常不必要)的相关信息,API通过这些令牌信息来授予客户端的数据访问权限。
客户端配置:
https://www.cnblogs.com/roubaozidd/p/16591358.html
https://www.cnblogs.com/easy5weikai/p/17198549.html
https://zhuanlan.zhihu.com/p/364933146
IdentityServer4
基础教程:https://www.cnblogs.com/haogj/p/12591332.html
IdentityServer4
授权认证(成功):https://www.cnblogs.com/nsky/p/10352678.html
IdentityServer4
目录授权认证:
https://blog.csdn.net/weixin_43394129/article/details/132444328
IdentityServer4 各客户端授权教程:https://www.jianshu.com/p/f28d394a92bd
IdentityServer4 数据持久化:https://www.cnblogs.com/fanfan-90/p/16269532.html
分模块保护Api:https://www.cnblogs.com/fanfan-90/p/16251758.html
IdentityServer4一些概念记录:https://www.cnblogs.com/Dragon_Compass/articles/17653240.html
IdentityServer4
客户端:https://www.cnblogs.com/wjx-blog/p/11054243.html
IdentityServer4 自定义授权模式:https://www.cnblogs.com/fengchao1000/p/11454704.html
IdentityServer4
客户端密码模式登录:https://www.cnblogs.com/huiteresa/p/17601289.html
IdentityServer4
客户端授权教程:https://www.jianshu.com/p/f28d394a92bd
NetCore Identity 密码加密:https://www.cnblogs.com/haido/p/16033463.html
IdentityServer4-登录:https://www.cnblogs.com/liyouming/p/8822507.html
identity service4 返回自定义Claims:
https://blog.csdn.net/dacong/article/details/106166645
https://www.cnblogs.com/sunnytrudeau/p/15631169.html
https://blog.csdn.net/sD7O95O/article/details/85594272
IdentityServer4简介及客户端模式和用户密码模式的应用:https://www.cnblogs.com/yaopengfei/p/13153559.html
IdentityServer4 配置Scope
https://www.cnblogs.com/xhznl/p/13223964.html
角色授权策略
https://codeleading.com/article/57225396696/
普通客户端与API授权
https://www.cnblogs.com/weihengblogs/p/17030496.html
账号密码验证:https://www.cnblogs.com/chenxf1117/p/13171418.html
[Authorize("OAScope")]
[Authorize(Policy = "orderScope")]
services.AddIdentityServer()
services.AddDeveloperSigningCredential()
//添加证书加密方式,执行该方法,会先判断tempkey.rsa证书文件是否存在,如果不存在的话,就创建一个新的tempkey.rsa证书文件,如果存在的话,就使用此证书文件。
services.AddInMemoryApiResources(TestConfig.GetApiResources())
//把受保护的Api资源添加到内存中
services.AddInMemoryClients(TestConfig.GetClients())
//客户端配置添加到内存中
services.AddTestUsers(TestConfig.GetTestUsers())
//测试的用户添加进来
services.AddDeveloperSigningCredential();
app.UseIdentityServer();
//这个必须在UseRouting和UseEndpoints中间。如果IdentityServer服务端和API端要写在一起,那么这个必须在UseAuthorization和UseAuthentication的上面。
//配置认证
services.AddAuthentication("Bearer")
// 配置授权策略
services.AddAuthorization(options =>{})
客户端可访问资源
new Client
{
ClientId = "client",
ClientName = "clientName",
AllowedGrantTypes = GrantTypes.ClientCredentials,
ClientSecrets = { new Secret("secret".Sha256()) },
AllowedScopes = { "api1" }
}
API认证
services.AddAuthentication("Bearer")
.AddJwtBearer("Bearer", options =>
{
options.Authority = "http://localhost:58653";
options.RequireHttpsMetadata = false;
options.Audience = "api1";
});
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
}
API接口
[Route("api/[controller]")]
[ApiController]
public class OrderController : ControllerBase
{
[HttpGet]
public IActionResult Get()
{
string[] orders = { "A", "B", "C" };
return Ok(orders);
}
}
API配置策略授权
builder.Services.AddAuthorization(options => { options.AddPolicy("ApiScope", policy => //ApiScope对应控制器授权名称 { policy.RequireAuthenticatedUser(); policy.RequireClaim("scope", "orderApi");//orderApi自定义名称 }); });
API定义
[Route("api/[controller]")] [ApiController] public class OrderController : ControllerBase { [HttpGet] [Authorize(Policy = "ApiScope")]//与上面的策略授权一致 public IActionResult Orders() { string[] orders = { "order1", "order2" , "order3" }; return Ok(orders); } }
配置角色策略
builder.Services.AddAuthorization(options => { options.AddPolicy("EmployeeOnly", policy => policy.RequireRole("Admin")); });
角色API
[Authorize(Roles = "Admin")]
参考:https://zhuanlan.zhihu.com/p/566985775
https://www.cnblogs.com/fanfan-90/p/16269532.html
【IdentityServer4】基础:https://www.cnblogs.com/fanfan-90/p/16204991.html
IdentityServer4示例:https://github.com/IdentityServer
创建自己的IdentityServer4存储库:
https://www.cnblogs.com/nirvanan/articles/14600817.html
https://www.cnblogs.com/haogj/p/12621131.html
IdentityServer4身份验证、授权
https://blog.csdn.net/qq_34202873/article/details/112981132
IdentityServer4下载地址:https://github.com/IdentityServer/IdentityServer4.Quickstart.UI
IdentityServer4客户端获取Token的方法:https://www.cnblogs.com/wjx-blog/p/11052821.html
内存配置方式:
public static class Config { public static IEnumerable<IdentityResource> IdentityResources=> new IdentityResource[] { new IdentityResources.OpenId() }; // Defining an API Resource public static IEnumerable<ApiResource> Apis => new List<ApiResource>{ new ApiResource("Order.WebApi", "订单服务"){ Scopes=new[]{ "Order.Read","Order.Write" } }, new ApiResource("Product.WebApi", "产品服务") }; //4.x新增ApiScope public static IEnumerable<ApiScope> GetApiScopes=>new[] { new ApiScope("Order.Read") , new ApiScope("Order.Write") }; // Defining Client public static IEnumerable<Client> Clients => new List<Client> { new Client { //没有交互式用户,使用clientid/secret进行身份验证 AllowedGrantTypes=GrantTypes.ClientCredentials, ClientId="client", ClientSecrets={new Secret("secret".Sha256())}, //客户端可以访问的范围 AllowedScopes={ "Order.Read", "Order.Write" } } }; }
第一步:创建 NetCore 项目
第二步:安装 Nuget 包
IdentityServer4
IdentityServer4.AspNetIdentity
IdentityServer4.EntityFramework
Microsoft.AspNetCore.Identity.EntityFrameworkCore
Microsoft.EntityFrameworkCore.SqlServer
Microsoft.EntityFrameworkCore.Tools
第三步:配置(appsettings.json)数据库连接字符串
"ConnectionStrings": { "DefaultConnection": "Server=.;database=microids4db;uid=sa;pwd=.mssql.;TrustServerCertificate=True;" }
第四步:配置数据库服务
//读取数据库连接 var connectionString = builder.Configuration.GetConnectionString("DefaultConnection"); /**********************************IdentityServer4持久化配置**********************************/ //添加用户数据上下文 ApplicationDbContext builder.Services.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer(connectionString)); builder.Services.AddIdentity<IdentityUser, IdentityRole>() .AddEntityFrameworkStores<ApplicationDbContext>() .AddDefaultTokenProviders(); //添加配置数据上下文 ConfigurationDbContext、操作数据上下文 PersistedGrantDbContext、用户持久化 builder.Services.AddIdentityServer() .AddConfigurationStore(options => { options.ConfigureDbContext = builder => { builder.UseSqlServer(connectionString, sql => sql.MigrationsAssembly("Micro.IdentityServer4V4")); }; }) .AddOperationalStore(options => { options.ConfigureDbContext = builder => { builder.UseSqlServer(connectionString, sql => sql.MigrationsAssembly("Micro.IdentityServer4V4")); }; //token配置 options.EnableTokenCleanup = true; options.TokenCleanupInterval = 30; }) .AddAspNetIdentity<IdentityUser>() .AddDeveloperSigningCredential();
第五步:控制台迁移
1.迁移操作数据
add-migration InitialIdentityServerPersistedGrantDbMigration -c PersistedGrantDbContext -o Migrations/PersistedGrantDb
update-database -Context PersistedGrantDbContext
2.迁移资源、客户端
add-migration InitialIdentityServerConfigurationDbMigration -c ConfigurationDbContext -o Migrations/ConfigurationDb
update-database -Context ConfigurationDbContext
3.迁移身份
add-migration InitialApplication -c ApplicationDbContext -o Migrations/ApplicationDb
update-database -Context ApplicationDbContext
4.数据库表结构
5.数据关系
参考:https://cloud.tencent.com/developer/article/1151268
API资源配置角色
public ApiResource(string name, string displayName, IEnumerable<string> claimTypes) { if (name.IsMissing()) throw new ArgumentNullException(nameof(name)); Name = name; DisplayName = displayName; Scopes.Add(new Scope(name, displayName)); if (!claimTypes.IsNullOrEmpty()) { foreach (var type in claimTypes) { UserClaims.Add(type); } } }
通过角色控制API访问权限
[Authorize(Roles = "superadmin")]
授权配置角色
new ApiResource("api1", "My API",new List<string>(){JwtClaimTypes.Role})
如何使用已有用户数据自定义Claim,实现IResourceOwnerPasswordValidator接口
客户端授权
https://www.jianshu.com/p/f28d394a92bd
安装模板,参考:https://blog.csdn.net/tx1721110240/article/details/112392277
输入CMD命令1:dotnet new install identityserver4.templates
输入CMD命令2
:dotnet new is4ui
后台使用Token请求API
using Dotnet.WebApi.Ids4.MvcApp.Models; using IdentityModel.Client; using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.IdentityModel.Protocols.OpenIdConnect; using System.Diagnostics; namespace Micro.Ids4App.Controllers { [Authorize] public class HomeController : Controller { ...... /// <summary> /// 获取API资源。 /// </summary> /// <returns></returns> public async Task<IActionResult> ApiData() { //获取accessToken var accessToken = await HttpContext.GetTokenAsync(OpenIdConnectParameterNames.AccessToken); //请求API资源 var httpClient = new HttpClient(); //将获取到的AccessToken以Bearer的方案设置在请求头中 httpClient.SetBearerToken(accessToken); //向API资源服务器请求受保护的API var data = await httpClient.GetAsync("https://localhost:6002/api/WeatherForecast"); if (data.IsSuccessStatusCode) { var r = await data.Content.ReadAsStringAsync(); ViewBag.ApiData = r; } else { ViewBag.ApiData = $"获取API数据失败。状态码:{data.StatusCode}"; } return View(); } } }
集成 AspNetIdentity
参考:https://www.cnblogs.com/easy5weikai/p/17201155.html
//获取数据库连接字符串,从appsettings.json中读取。 var connetionString = builder.Configuration.GetConnectionString("Ids4Connection"); //注册AppDbContext服务。 builder.Services.AddDbContext<AppDbContext>(options => { options.UseSqlServer(connetionString); }); //注册Asp.Net Core Identity服务。 builder.Services.AddIdentity<IdentityUser, IdentityRole>() .AddEntityFrameworkStores<AppDbContext>() .AddDefaultTokenProviders(); var ids4Builder = builder.Services.AddIdentityServer(). .AddAspNetIdentity<IdentityUser>(); //使用持久化用户
自定义实现,参考:https://www.cnblogs.com/nirvanan/articles/14600817.html
services.AddIdentityServer() // existing registrations .AddClientStore<MyCustomClientStore>() .AddCorsPolicyService<MyCustomCorsPolicyService>() .AddResourceStore<MyCustomResourcesStore>() .AddPersistedGrantStore<MyCustomPersistedGrantStore>() .AddDeviceFlowStore<MyCustomDeviceFlowStore>(); // For manual temp data stores services.AddTransient<IAuthorizationCodeStore, MyCustomAuthorizationCodeStore>(); services.AddTransient<IRefreshTokenStore, MyCustomRefreshTokenStore>(); services.AddTransient<IReferenceTokenStore, MyCustomReferenceTokenStore>(); services.AddTransient<IUserConsentStore, MyCustomUserConsentStore>();