文章目录
一、IdentityServer4是什么?
IdentityServer4 是为ASP.NET Core 2.系列量身打造的一款基于 OpenID Connect 和 OAuth 2.0 认证框架。将identityserver部署在你的应用中,具备如下的特点可以为你的应用(如网站、本地应用、移动端、服务)做集中式的登录逻辑和工作流控制。IdentityServer是完全实现了OpenID Connect协议标准。在各种类型的应用上实现单点登录登出。为各种各样的客户端颁发access token令牌,如服务与服务之间的通讯、网站应用、SPAS和本地应用或者移动应用等。
二、使用步骤
1.创建一个认证服务项目,命名IdentityServer
2.引入IdentityServer4库 版本3.1.4
3.创建一个Config配置类
4.定义一个api
范围(Scopes)用来定义系统中你想要保护的资源,比如 API。由于当前演练中我们使用的是内存配置 —— 添加一个 API,你需要做的只是创建一个 ApiResource 类型的实例,并为它设置合适的属性(代码示例):
public static IEnumerable<ApiResource> GetApis()
{
return new List<ApiResource>
{
new ApiResource("api", "Demo API")
{
ApiSecrets = { new Secret("secret".Sha256()) }
},
new ApiResource("secretapi", "secretapi")
{
ApiSecrets = { new Secret("secret".Sha256()) }
}
};
}
5.定义客户端
下一步是定义能够访问上述 API 的客户端。在该场景中,客户端不会有用户参与交互,并且将使用 IdentityServer 中所谓的客户端密码(Client Secret)来认证。(代码示例):
public static IEnumerable<Client> GetClients()
{
return new List<Client>
{
//走客户端模式
new Client
{
ClientId = "client",
ClientSecrets = { new Secret("secret".Sha256()) },
AllowedGrantTypes = GrantTypes.ClientCredentials,
//过期时间
AccessTokenLifetime=100000000,
AllowedScopes = { "api"
}
},
//走账号密码模式
new Client()
{
ClientId = "apiClientPassword",
ClientSecrets = { new Secret("apiSecret".Sha256()) },
AccessTokenLifetime = 1800,//设置AccessToken过期时间
AllowedGrantTypes =GrantTypes.ResourceOwnerPassword,
//RefreshTokenExpiration = TokenExpiration.Absolute,//刷新令牌将在固定时间点到期
AbsoluteRefreshTokenLifetime = 2592000,//RefreshToken的最长生命周期,默认30天
RefreshTokenExpiration = TokenExpiration.Sliding,//刷新令牌时,将刷新RefreshToken的生命周期。RefreshToken的总生命周期不会超过AbsoluteRefreshTokenLifetime。
SlidingRefreshTokenLifetime = 3600,//以秒为单位滑动刷新令牌的生命周期。
//按照现有的设置,如果3600内没有使用RefreshToken,那么RefreshToken将失效。即便是在3600内一直有使用RefreshToken,RefreshToken的总生命周期不会超过30天。所有的时间都可以按实际需求调整。
AllowOfflineAccess = true,//如果要获取refresh_tokens ,必须把AllowOfflineAccess设置为true
AllowedScopes = new List<string>
{
"secretapi",
StandardScopes.OfflineAccess, //如果要获取refresh_tokens ,必须在scopes中加上OfflineAccess
StandardScopes.OpenId,//如果要获取id_token,必须在scopes中加上OpenId和Profile,id_token需要通过refresh_tokens获取AccessToken的时候才能拿到(还未找到原因)
StandardScopes.Profile//如果要获取id_token,必须在scopes中加上OpenId和Profile
}
}
};
}
6.添加用户
就像基于内存存储的资源(即 范围 Scopes)和客户端一样,对于用户也可以这样做。
注意:查看基于 ASP.NET Identity 的快速入门以获得更多关于如何正确存储和管理用户账户的信息。
TestUser 类型表示一个测试用户及其身份信息。(代码示例):
public static List<TestUser> GetUsers()
{
return new List<TestUser>()
{
new TestUser()
{
//用户名
Username="apiUser",
//密码
Password="apiUserPassword",
//用户Id
SubjectId="0",
Claims=new List<Claim>(){
new Claim(ClaimTypes.Role,"admin")
}
}
};
7.配置Identityserver
为了让 IdentityServer 使用你的 Scopes 和 客户端 定义,你需要向 ConfigureServices 方法中添加一些代码。你可以使用便捷的扩展方法来实现 —— 它们在幕后会添加相关的存储和数据到 DI 系统中(代码示例):
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
//把配置添加到内存
services.AddIdentityServer().AddInMemoryApiResources(Config.GetApis())
.AddInMemoryIdentityResources(Config.GetIdentityResources())
.AddTestUsers(Config.GetUsers())
.AddInMemoryClients(Config.GetClients())
.AddDeveloperSigningCredential();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseRouting();
app.UseAuthorization();
//配置UseIdentityServer
app.UseIdentityServer();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
8.整个Config代码
public class Config
{
public static IEnumerable<IdentityResource> GetIdentityResources()
{
return new List<IdentityResource>
{
new IdentityResources.OpenId(),
new IdentityResources.Profile(),
};
}
public static List<TestUser> GetUsers()
{
return new List<TestUser>()
{
new TestUser()
{
//用户名
Username="apiUser",
//密码
Password="apiUserPassword",
//用户Id
SubjectId="0",
Claims=new List<Claim>(){
new Claim(ClaimTypes.Role,"admin")
}
}
};
}
public static IEnumerable<ApiResource> GetApis()
{
return new List<ApiResource>
{
new ApiResource("api", "Demo API")
{
ApiSecrets = { new Secret("secret".Sha256()) }
},
new ApiResource("secretapi", "secretapi")
{
ApiSecrets = { new Secret("secret".Sha256()) }
}
};
}
public static IEnumerable<Client> GetClients()
{
return new List<Client>
{
//走客户端模式
new Client
{
ClientId = "client",
ClientSecrets = { new Secret("secret".Sha256()) },
AllowedGrantTypes = GrantTypes.ClientCredentials,
//过期时间
AccessTokenLifetime=100000000,
AllowedScopes = { "api"
}
},
//走账号密码模式
new Client()
{
ClientId = "apiClientPassword",
ClientSecrets = { new Secret("apiSecret".Sha256()) },
AccessTokenLifetime = 1800,//设置AccessToken过期时间
AllowedGrantTypes =GrantTypes.ResourceOwnerPassword,
//RefreshTokenExpiration = TokenExpiration.Absolute,//刷新令牌将在固定时间点到期
AbsoluteRefreshTokenLifetime = 2592000,//RefreshToken的最长生命周期,默认30天
RefreshTokenExpiration = TokenExpiration.Sliding,//刷新令牌时,将刷新RefreshToken的生命周期。RefreshToken的总生命周期不会超过AbsoluteRefreshTokenLifetime。
SlidingRefreshTokenLifetime = 3600,//以秒为单位滑动刷新令牌的生命周期。
//按照现有的设置,如果3600内没有使用RefreshToken,那么RefreshToken将失效。即便是在3600内一直有使用RefreshToken,RefreshToken的总生命周期不会超过30天。所有的时间都可以按实际需求调整。
AllowOfflineAccess = true,//如果要获取refresh_tokens ,必须把AllowOfflineAccess设置为true
AllowedScopes = new List<string>
{
"secretapi",
StandardScopes.OfflineAccess, //如果要获取refresh_tokens ,必须在scopes中加上OfflineAccess
StandardScopes.OpenId,//如果要获取id_token,必须在scopes中加上OpenId和Profile,id_token需要通过refresh_tokens获取AccessToken的时候才能拿到(还未找到原因)
StandardScopes.Profile//如果要获取id_token,必须在scopes中加上OpenId和Profile
}
}
};
}
}
9.启动,运行
现在,如果你运行服务器并将浏览器导航到 http://localhost:5000/.well-known/openid-configuration,你应该看能到所谓的 发现文档。你的客户端和 API 将使用这些信息来下载所需要的配置数据。
10.通过postman进行测试
请求地址:http://localhost:5000/connect/token
-
测试客户端模式
参数:
grant_type=client_credentials
client_id=client
client_secret=secret
Scope=api
-
测试密码模式
参数:
grant_type=password
client_id=client
client_secret=secret
Scope=api offline_access (必须配置offline_access,才能获取到refresh_token)
Username=apiUser
Password=apiUserPassword