IdentityServer4的最佳使用
简介
本人做微服务项目也有一段时间了,在微服务中让我感触颇深的就是这个IdentityServer4了,ID4(IdentityServer4的简称)中涉及的概念颇多,本文不谈概念(我怕读者没耐心看下去),在这分享下我个人的使用心得。
目录
1. ID4简介
2. ID4使用
ID4简介
相信大家都知道面向对象中的封装(把通用的功能封装起来,减少程序中大量重复代码),我们知道在一个单体系统中有很多的重复模块,例如:身份认证、权限控制检查等,在单体系统中,这些都可以使用aop统一在一个地方控制。而在分布式系统,每个系统都需要进行身份认证、权限检查等。这时,每个系统都得写一套同样的代码来进行这些控制,我们能不能像单体系统那样在一个地方进行这些流程呢?这时我们可以使用IdentityServer4来实现。
IdentityServer4是一个集成 身份认证和授权 的组件,使用OpenId Connect(身份识别框架) 和 Auth2.0(授权框架)来进行身份认证和授权的。
ID4使用
我这里只列出几个主要的类,其它,可以下载项目来看。关于如何使用,代码有点多,我比较懒,就没怎么讲解,感兴趣的小伙伴可以加个QQ:1983702356 来讨论下。
项目地址: https://github.com/MapleWithoutWords/IdentityServer4Demo
(注意:下载项目后,记得把数据库链接字符串改下)项目环境:
- .net core 2.2
- IdentityServer 2.5
- Mysql 8
项目结构:
WEBAPPLICATION1 (IDENTITYSERVER4)项目,安装 INSTALL-PACKAGE IDENTITYSERVER4 -VERSION 2.5.0,
以下几个类比较关键
Config.cs。主要是获取身份资源
1
2
3
4
5
6
7
8
9
10
11
12public class Config
{
public static IEnumerable<IdentityResource> GetIdentityResources()
{
return new List<IdentityResource>
{
new IdentityResources.OpenId(), //必须要添加,否则报无效的 scope 错误
new IdentityResources.Profile(),
new IdentityResources.Email()
};
}
}TestClientStore.cs 加载IdentityServer4的client
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37/// <summary>
/// 加载IdentityServer4的client
/// </summary>
public class TestClientStore : IClientStore
{
/// <summary>
/// Service层中的一个接口
/// </summary>
public IClientService ClientSvc { get; set; }
public TestClientStore(IClientService ClientSvc)
{
this.ClientSvc = ClientSvc;
}
public async Task<Client> FindClientByIdAsync(string clientId)
{
var dto = await ClientSvc.FindClientByIdAsync(clientId);
if (dto==null)
{
return null;
}
var scopes = dto.APIResources.Select(e => e.Name).ToList();
scopes.Add(IdentityServerConstants.StandardScopes.OpenId);
scopes.Add(IdentityServerConstants.StandardScopes.Profile);
return new Client
{
ClientId = dto.Client.Id,//API账号、客户端Id
AllowedGrantTypes = GrantTypes.ResourceOwnerPassword,
ClientSecrets =
{
new Secret(dto.Client.Secret.Sha256())//秘钥
},
AllowedScopes = scopes//这个账号支持访问哪些应用
};
}
}TestReourceStore.cs,加载IdentityServer的APIResource
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39/// <summary>
/// 加载IdentityServer的APIResource
/// </summary>
public class TestReourceStore : IResourceStore
{
public IApiResourceService resourceSvc { get; set; }
public TestReourceStore(IApiResourceService resourceSvc)
{
this.resourceSvc = resourceSvc;
}
public async Task<ApiResource> FindApiResourceAsync(string name)
{
var entity = await resourceSvc.GetByNameAsync(name);
return new ApiResource(entity.Name,entity.DisplayName);
}
public async Task<IEnumerable<ApiResource>> FindApiResourcesByScopeAsync(IEnumerable<string> scopeNames)
{
var list = await resourceSvc.GetDatasByNamesAsync(scopeNames);
return list.Select(e=>new ApiResource(e.Name,e.DisplayName));
}
public async Task<IEnumerable<IdentityResource>> FindIdentityResourcesByScopeAsync(IEnumerable<string> scopeNames)
{
return Config.GetIdentityResources().Where(e => scopeNames.Contains(e.Name)).ToList();
}
public async Task<Resources> GetAllResourcesAsync()
{
var list = await resourceSvc.GetNoramlAll();
var resouces = list.Select(e => new ApiResource(e.Name, e.DisplayName)).ToList();
return new Resources
{
ApiResources = resouces
};
}
}TestResourceOwnerPasswordValidator.cs,IdentityServer4登录验证
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34/// <summary>
/// IdentityServer4登录验证
/// </summary>
public class TestResourceOwnerPasswordValidator : IResourceOwnerPasswordValidator
{
public IUserService UserSvc { get; set; }
public TestResourceOwnerPasswordValidator(IUserService UserSvc)
{
this.UserSvc = UserSvc;
}
public async Task ValidateAsync(ResourceOwnerPasswordValidationContext context)
{
string account = context.UserName;
string pwd = context.Password;
var loginResult = await UserSvc.Login(account, pwd);
if (loginResult == null)
{
context.Result = new GrantValidationResult(TokenRequestErrors.InvalidGrant, "invalid custom credential");
return;
}
context.Result = new GrantValidationResult(
subject: context.UserName,
authenticationMethod: "custom",
claims: new Claim[] {
new Claim("Name",context.UserName),
new Claim("UserId",loginResult.Id),
new Claim("Roles","Admin,Contact"), //模拟获取登录用户的角色信息
new Claim("Premissions","List,Delete") //模拟获取登录用户的权限信息
});
}
}ProfileService.cs,用户信息
1
2
3
4
5
6
7
8
9
10
11
12
13public class ProfileService : IProfileService
{
public async Task GetProfileDataAsync(ProfileDataRequestContext context)
{
var claims = context.Subject.Claims.ToList();
context.IssuedClaims = claims.ToList();
}
public async Task IsActiveAsync(IsActiveContext context)
{
context.IsActive = true;
}
}
- Startup类
1 |
public class Startup |
- WebApplication3 API项目,修改Startup,并添加一个控制器,在方法上打上一个标签
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication("Bearer")
.AddIdentityServerAuthentication(options =>
{
options.Authority = "http://localhost:9500";//identity server 地址
options.RequireHttpsMetadata = false;
});
string conStr = Configuration["connectionString"];
services.AddDbContext<TestDbContext>(options =>
{
options.UseMySql(conStr);
});
///依赖注入Service层
AddSigletons(services);
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
}
public void AddSigletons(IServiceCollection services)
{
var assem = Assembly.Load("Test.Service");
var list = assem.GetTypes().Where(e => e.IsAbstract == false && typeof(ISignFac).IsAssignableFrom(e));
foreach (var instanType in list)
{
foreach (var item in instanType.GetInterfaces())
{
services.AddSingleton(item, instanType);
}
}
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseAuthentication();
app.UseMvc();
}
}
运行CONSOLEAPP1控制台项目, 生成数据库,添加几条数据
运行效果
在 WebApplication1 目录下运行cmd命令 dotnet run ,启动IdentitServer4,端口是9500
运行项目 WebApplication3 ,端口是5000
当我们直接调用 WebApplication3 API中的方法时,发现返回状态码为 401
请求Id4,复制返回的 access_token
再请求WebApplication3 API,并在报文头带上token
结束语
个人认为我这种使用方式和其它使用方式最大的好处就是,可以写一个IdentityServer4的Client、APIResource增删改查,然后因为每次请求的时候都是从数据库读取数据的,如果数据被修改了,会立即生效。
最新文章
- C#_Express-ickd接口
- TcpListener 类
- RCP:给GEF编辑器添加网格和标尺。
- VC6在win7环境下无法添加以及打开现有文件的解决办法
- 使用Windows安装的最高版本IE内核加载内嵌页(转载)
- HDU 3038 How Many Answers Are Wrong (并查集)
- Ajax防止重复提交
- [Javascript] Drawing Styles on HTML5 Canvas
- 数据结构——HDU1312:Red and Black(DFS)
- centos 安装 mongo3.0
- .NET(C#):使用XPath查询带有命名空间(有xmlns)的XML
- CountDownLatch和CyclicBarrier的区别(转)
- Android圆弧形ListView的实现
- [Python Study Notes] 编程仪式感的Hello World!
- CentOS 安装 Redis 5
- SpringBoot与任务
- @suppresswarnings(unchecked)的作用
- Oracle数据库mybatis 插入空值时报错(with JdbcType OTHER)
- jenkins 项目发布脚本
- [NLP/Attention]关于attention机制在nlp中的应用总结