前面已经阐述了单点登录统一认证的核心框架基础 (一)IdentityServer 4 基础,接下来就进行简单实现
开发工具及框架:
Visual Studio
.NET CORE 版本: 2.1
NuGet包:IdentityServer 4
一、新建 IdentityServer 4 认证应用程序(快速创建/手动创建)
1.手动使用 VS 创建
打开 VS,新建 ASP.NET Core 2.1 应用程序 QuickStart
展开项目,右键依赖项,选择管理 NuGet 程序包,输入 IdentityServer 4 选择低于 3.0 版本安装。
在项目下新建 Config.cs 文件
(.NET CORE 2.1 对应的 Microsoft.AspNetCore.Razor.Design 版本为 2.1.2,打开 csproj 文件修改)
2.使用控制台快速创建
md quickstart cd quickstart md src cd src dotnet new is4empty -n IdentityServer cd.. dotnet new sln -n Quickstart dotnet sln add .srcIdentityServerIdentityServer.csproj
这将创建以下基础项目文件及添加 IdentityServer 项目:
PropertieslaunchSettings.json 配置文件
IdentityServer.csproj 项目文件
Program.cs 和 Startup.cs 主应用程序入口点
Config.cs IdentityServer 资源和客户端配置文件
注:PropertieslaunchSettings.json 配置文件包含运行端口,如果需要修改可修改该文件。
3.定义 API 资源
API 是系统中要保护的资源,资源定义可以通过多种方式加载。打开 Config.cs 文件,增加 API 资源
public static IEnumerable<ApiResource> GetApis() { return new List<ApiResource> { new ApiResource("api1", "My API") }; }
4.定义客户端
客户端用于访问 API 资源,还是打开 Config.cs 文件,增加客户端
public static IEnumerable<Client> GetClients() { return new List<Client> { new Client { ClientId = "client", // no interactive user, use the clientid/secret for authentication AllowedGrantTypes = GrantTypes.ClientCredentials, // secret for authentication ClientSecrets = { new Secret("secret".Sha256()) }, // scopes that client has access to AllowedScopes = { "api1" } } }; }
5.配置 IdentityServer 4
前面已经引入了 NuGet 包 IdentityServer 4,所以直接打开 Startup.cs 文件配置 IdentityServer 4
public void ConfigureServices(IServiceCollection services) { var builder = services.AddIdentityServer() .AddInMemoryIdentityResources(Config.GetIdentityResources()) .AddInMemoryApiResources(Config.GetApis()) .AddInMemoryClients(Config.GetClients()); // omitted for brevity }
到此,一个基础的 IdentityServer 4 身份认证服务器已配置完成,运行服务器并打开 http://localhost:5000/.well-known/openid-configuration 可以看到端点配置文件,客户端和 API 会通过该文件获取对于信息。
二、后台 API 服务
有了身份认证服务器,接下来就需要 API 服务。
1.手动创建
右键解决方案,添加新建项目 Api,选择 ASP.NET Core 应用程序,选择 Web 应用程序(模型视图控制器),包含控制器是便于后续增加 Swagger 接口文档。
2.控制台快速创建(若.NET CORE 版本高于2.1需要修改配置文件,推荐使用手动创建方法)
打开控制台,进入项目,执行以下命令
cd quickstart
cd src
dotnet new web -n Api
cd.. dotnet sln add .srcApiApi.csproj
项目创建完成后,修改 PropertieslaunchSettings.json 配置文件的运行端口为 5001(认证服务器端口为 5000)。
"applicationUrl": "http://localhost:5001"
3.新增 Controllers
添加新文件夹 Controllers 和新控制器 IdentityController,VS 创建的项目直接新增 IdentityController 控制器即可。
[Route("identity")] [Authorize] public class IdentityController : ControllerBase { [HttpGet] public IActionResult Get() { return new JsonResult(from c in User.Claims select new { c.Type, c.Value }); } }
4.配置依赖
将身份验证服务添加到DI(依赖注入),并将身份验证中间件添加到管道。打开 Api 的 Startup.cs 文件。
public class Startup { public void ConfigureServices(IServiceCollection services) { services.AddMvcCore() .AddAuthorization() .AddJsonFormatters(); services.AddAuthentication("Bearer") .AddJwtBearer("Bearer", options => { options.Authority = "http://localhost:5000"; options.RequireHttpsMetadata = false; options.Audience = "api1"; }); } public void Configure(IApplicationBuilder app) { app.UseAuthentication(); app.UseMvc(); } }
AddAuthentication 将身份验证服务添加到DI并配置"Bearer"为默认方案,UseAuthentication 将身份验证中间件添加到管道中,以便对主机的每次调用都将自动执行身份验证。
http://localhost:5001/identity 在浏览器上导航至控制器应返回401状态代码。这表示 API 现在受 IdentityServer 保护,访问需要凭据。
至此,后台 API 服务已经创建完成,接下来创建一个客户端进行认证访问及 API 调用。
三、创建客户端
1.手动创建
右键解决方案,新建控制台应用
2.快速创建
cd quickstart cd src dotnet new console -n Client cd .. dotnet sln add .srcClientClient.csproj
3.修改启动文件
打开 NuGet 程序包,添加 IdentityModel,并修改 Program.cs 文件如下
using IdentityModel.Client; using Newtonsoft.Json.Linq; using System; using System.Net.Http; using System.Threading.Tasks; namespace Client { public class Program { private static async Task Main() { // discover endpoints from metadata var client = new HttpClient(); var disco = await client.GetDiscoveryDocumentAsync("http://localhost:5000"); if (disco.IsError) { Console.WriteLine(disco.Error); return; } // request token var tokenResponse = await client.RequestClientCredentialsTokenAsync(new ClientCredentialsTokenRequest { Address = disco.TokenEndpoint, ClientId = "client", ClientSecret = "secret", Scope = "api1" }); if (tokenResponse.IsError) { Console.WriteLine(tokenResponse.Error); return; } Console.WriteLine(tokenResponse.Json); Console.WriteLine(" "); Console.ReadLine(); // call api var apiClient = new HttpClient(); apiClient.SetBearerToken(tokenResponse.AccessToken); var response = await apiClient.GetAsync("http://localhost:5001/identity"); if (!response.IsSuccessStatusCode) { Console.WriteLine(response.StatusCode); } else { var content = await response.Content.ReadAsStringAsync(); Console.WriteLine(JArray.Parse(content)); } Console.ReadLine(); } } }
至此一个简单的包含身份服务器,API 服务器,控制台应用的项目完成,运行身份服务器,API 服务器,控制台应用,控制台应用输出如下
四、添加需要用户名和密码的客户端
1.添加测试用户
修改 IdentityServer 认证服务的 Config.cs文件
using IdentityServer4.Test; public static List<TestUser> GetUsers() { return new List<TestUser> { new TestUser { SubjectId = "1", Username = "alice", Password = "password" }, new TestUser { SubjectId = "2", Username = "bob", Password = "password" } }; }
然后在 Startup.cs 中注册测试用户
public void ConfigureServices(IServiceCollection services) { // configure identity server with in-memory stores, keys, clients and scopes services.AddIdentityServer() .AddInMemoryApiResources(Config.GetApiResources()) .AddInMemoryClients(Config.GetClients()) .AddTestUsers(Config.GetUsers()); }
2.添加新客户端配置
public static IEnumerable<Client> GetClients() { return new List<Client> { // other clients omitted... // resource owner password grant client new Client { ClientId = "ro.client", AllowedGrantTypes = GrantTypes.ResourceOwnerPassword, ClientSecrets = { new Secret("secret".Sha256()) }, AllowedScopes = { "api1" } } }; }
3.通过用户名和密码进行授权
修改控制台应用 Client 的 Program.cs 文件,增加新的授权方式
// request token var tokenResponse = await client.RequestPasswordTokenAsync(new PasswordTokenRequest { Address = disco.TokenEndpoint, ClientId = "ro.client", ClientSecret = "secret", UserName = "alice", Password = "password", Scope = "api1" }); if (tokenResponse.IsError) { Console.WriteLine(tokenResponse.Error); return; } Console.WriteLine(tokenResponse.Json);
新的客户端需要传输用户名和密码才能通过授权
更多 IdentityServer 示例请移步官方文档地址