快速入门IdentityServer4
-
概述
-
- 将 IdentityServer 添加到 ASP.NET Core 应用程序
- 配置 IdentityServer
- 为各种客户发行代币
- 保护 Web 应用程序和 API
- 添加对基于 EntityFramework 的配置的支持
- 添加对 ASP.NET 标识的支持
- 准备
- 安装模板
控制台窗口输入该命令,下载 IdentityServer 模板
dotnet new -i IdentityServer4.Templates //
-
- 创建项目
打开控制台窗口,请在控制台窗口键入以下命令
md quickstart //创建文件夹,文件夹名称quickstart cd quickstart //进入文件夹quickstart md src //创建文件夹,文件夹名称src cd src //进入文件夹src dotnet new is4empty -n IdentityServer //创建空项目,项目名称IdentityServer
命令执行完成后,将会创建以下文件
IdentityServer.csproj
- 项目文件和一个Properties\launchSettings.json
文件
Program.cs
和Startup.cs
- 主应用程序入口点
Config.cs
- IdentityServer 资源和客户端配置文件
如果需要使用Visual Studio作为开发工具,我们还需要创建解决方案文件,命令如下:
dotnet new sln -n Quickstart
我们需要将文件添加至解决方案,命令如下:(请注意路径是否正确)
dotnet sln add .\src\IdentityServer\IdentityServer.csproj
- 开始学习
项目创建成功之后,将会为我们创建config 文件,Config文件的代码如下:
1 using IdentityServer4.Models; 2 using System.Collections.Generic; 3 4 namespace IdentityServer 5 { 6 public static class Config 7 { 8 public static IEnumerable<IdentityResource> IdentityResources => 9 new IdentityResource[] 10 { 11 new IdentityResources.OpenId() 12 }; 13 14 public static IEnumerable<ApiScope> ApiScopes => 15 new ApiScope[] 16 { }; 17 18 public static IEnumerable<Client> Clients => 19 new Client[] 20 { }; 21 } 22 }View Code
- 自定义API范围
1 public static IEnumerable<ApiScope> ApiScopes => 2 new List<ApiScope> 3 { 4 new ApiScope("api1", "MyApiName") 5 };
//ApiScope构造函数提供两个参数,第一个参数为name,第二个参数为displayname
如果您在生产环境种使用自定义API范围,您为您的API提供一个逻辑名称很重要,开发人员将使用它通过您的身份服务器请求您的API,它应该用简单的术语向开发人员描述您的api,displayname为用户提供apiScope的描述名称
- 定义客户端
我们将要定义一个客户端应用程序,我们将用它来访问我们的API,对于这种情况,客户端没有交互式用户,并将使用IdentityServer使用客户端密钥进行身份验证。为此我们需要添加一个客户端
1 public static IEnumerable<Client> Clients => 2 new[] 3 { 4 new Client 5 { 6 ClientId = "client", 7 8 AllowedGrantTypes=GrantTypes.ClientCredentials, 9 10 ClientSecrets = 11 { 12 new Secret("secret","sha256") 13 }, 14 AllowedScopes = { "api1" } 15 } 16 };
您可以将 ClientId 和 ClientSecret 视为应用程序本身的登录名和密码。它向身份服务器标识您的应用程序,以便它知道哪个应用程序正在尝试连接到它。
- 配置身份服务器
在Startup.cs文件中的ConfigureServices方法种定义资源和客户端,代码如下:
1 public void ConfigureServices(IServiceCollection services) 2 { 3 // uncomment, if you want to add an MVC-based UI 4 //services.AddControllersWithViews(); 5 6 var builder = services.AddIdentityServer(options => 7 { 8 // see https://identityserver4.readthedocs.io/en/latest/topics/resources.html 9 options.EmitStaticAudienceClaim = true; 10 }) 11 .AddInMemoryIdentityResources(Config.IdentityResources) 12 .AddInMemoryApiScopes(Config.ApiScopes) 13 .AddInMemoryClients(Config.Clients); 14 15 // not recommended for production - you need to store your key material somewhere secure 16 builder.AddDeveloperSigningCredential(); 17 }
配置您的身份服务器之后,访问路径https://localhost:5001/.well-known/openid-configuration,我们将会看到发现文档,发现文档是身份服务器种的标准节点,您的客户端和API将使用该文档来查看必要的配置数据,节点文档如下:
1 { 2 "issuer":"https://localhost:5001", 3 "jwks_uri":"https://localhost:5001/.well-known/openid-configuration/jwks", 4 "authorization_endpoint":"https://localhost:5001/connect/authorize", 5 "token_endpoint":"https://localhost:5001/connect/token", 6 "userinfo_endpoint":"https://localhost:5001/connect/userinfo", 7 "end_session_endpoint":"https://localhost:5001/connect/endsession", 8 "check_session_iframe":"https://localhost:5001/connect/checksession", 9 "revocation_endpoint":"https://localhost:5001/connect/revocation", 10 "introspection_endpoint":"https://localhost:5001/connect/introspect", 11 "device_authorization_endpoint":"https://localhost:5001/connect/deviceauthorization", 12 "frontchannel_logout_supported":true, 13 "frontchannel_logout_session_supported":true, 14 "backchannel_logout_supported":true, 15 "backchannel_logout_session_supported":true, 16 "scopes_supported":[ 17 "openid", 18 "api1", 19 "offline_access" 20 ], 21 "claims_supported":[ 22 "sub" 23 ], 24 "grant_types_supported":[ 25 "authorization_code", 26 "client_credentials", 27 "refresh_token", 28 "implicit", 29 "urn:ietf:params:oauth:grant-type:device_code" 30 ], 31 "response_types_supported":[ 32 "code", 33 "token", 34 "id_token", 35 "id_token token", 36 "code id_token", 37 "code token", 38 "code id_token token" 39 ], 40 "response_modes_supported":[ 41 "form_post", 42 "query", 43 "fragment" 44 ], 45 "token_endpoint_auth_methods_supported":[ 46 "client_secret_basic", 47 "client_secret_post" 48 ], 49 "id_token_signing_alg_values_supported":[ 50 "RS256" 51 ], 52 "subject_types_supported":[ 53 "public" 54 ], 55 "code_challenge_methods_supported":[ 56 "plain", 57 "S256" 58 ], 59 "request_parameter_supported":true 60 }
在第一次启动时,IdentityServer 会为你创建一个开发者签名密钥,它是一个名为tempkey.jwk
. 您不必将该文件签入您的源代码管理,如果它不存在,它将被重新创建
- 添加API测试
创建API项目,命令如下:
dotnet new webapi -n Api
将API项目添加至解决方案
dotnet sln add .\src\Api\Api.csproj
修改API项目的应用配置,修改运行端口号,我们可以通过编辑Properties 文件夹中的launchSettings.json文件来执行此操作,将应用程序的URL设置更改为:
"applicationUrl": "https://localhost:6001"
- 添加控制器
我们新建一个类,为IdentityController,此测试类将用于测试授权要求,以及通过API可视化身份识别
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Threading.Tasks; 5 using Microsoft.AspNetCore.Authorization; 6 using Microsoft.AspNetCore.Mvc; 7 8 namespace Api.Controllers 9 { 10 [Route("identity")] 11 [Authorize] 12 public class IdentityController: ControllerBase 13 { 14 public IActionResult Get() 15 { 16 return new JsonResult(from c in User.Claims select new { c.Type, c.Value }); 17 } 18 } 19 }
添加NuGet包依赖项目:Microsoft.AspNetCore.Authentication.JwtBearer,我们可以手动添加,也可以执行如下命令:
dotnet add .\\src\\api\\Api.csproj package Microsoft.AspNetCore.Authentication.JwtBearer
- 配置
最后一步是将身份验证服务添加到DI(依赖注入) 并将身份验证中间件添加到管道中,这些操作将:
-
- 验证传入的令牌以确保它来自受信任者的发行者
- 验证令牌是否有效与此API一起使用
我们查看以下API中的Startup代码,我们将其更新如下:
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Threading.Tasks; 5 using Microsoft.AspNetCore.Builder; 6 using Microsoft.AspNetCore.Hosting; 7 using Microsoft.AspNetCore.HttpsPolicy; 8 using Microsoft.AspNetCore.Mvc; 9 using Microsoft.Extensions.Configuration; 10 using Microsoft.Extensions.DependencyInjection; 11 using Microsoft.Extensions.Hosting; 12 using Microsoft.Extensions.Logging; 13 using Microsoft.IdentityModel.Tokens; 14 using Microsoft.OpenApi.Models; 15 16 namespace Api 17 { 18 public class Startup 19 { 20 public Startup(IConfiguration configuration) 21 { 22 Configuration = configuration; 23 } 24 25 public IConfiguration Configuration { get; } 26 27 // This method gets called by the runtime. Use this method to add services to the container. 28 public void ConfigureServices(IServiceCollection services) 29 { 30 31 services.AddControllers(); 32 services.AddSwaggerGen(c => 33 { 34 c.SwaggerDoc("v1", new OpenApiInfo { Title = "Api", Version = "v1" }); 35 }); 36 37 services.AddAuthentication("Bearer").AddJwtBearer("Bearer", options => 38 { 39 options.Authority = "https://localhost:5001"; 40 41 options.TokenValidationParameters = new TokenValidationParameters 42 { 43 ValidateAudience = false 44 }; 45 }); 46 47 } 48 49 // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. 50 public void Configure(IApplicationBuilder app, IWebHostEnvironment env) 51 { 52 if (env.IsDevelopment()) 53 { 54 app.UseDeveloperExceptionPage(); 55 app.UseSwagger(); 56 app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "Api v1")); 57 } 58 59 app.UseHttpsRedirection(); 60 61 app.UseRouting(); 62 63 app.UseAuthentication(); 64 app.UseAuthorization(); 65 66 app.UseEndpoints(endpoints => 67 { 68 endpoints.MapControllers(); 69 }); 70 71 } 72 } 73 }View Code
AddAuthentication
将身份验证服务添加到 DI 并配置Bearer
为默认方案。
UseAuthentication
将身份验证中间件添加到管道中,因此每次调用主机时都会自动执行身份验证。
UseAuthorization
添加授权中间件以确保匿名客户端无法访问我们的 API 端点。
https://localhost:6001/identity
在浏览器上导航到控制器应返回 401 状态代码。这意味着您的 API 需要凭证并且现在受 IdentityServer 保护。