IdentityServer4 是Asp.net core的一个中间件,用于添加符合OpenId Connect和OAuth2.0规范的终端到Asp.net Core应用。在这里简单介绍一下Openid和OAuth2.0。html
OpenId:用户身份认证(Authentication )。当用户(End User)在微信、Google等OpenId提供者(OpenID Provider)平台注册帐户时会产生一个身份标识,这个身份标识就是OpenId,当用户登陆第三方应用(Relying Part)时若是Relying Part支持OpenId登陆,会生成一个带有重定向地址的Url跳至OpenId Provider平台登陆界面,用户登陆成功后,根据重定向地址带着OpenId跳回Relying Part,标识着用户身份认证成功,该用户在OpenId Provider平台有注册。Relying Part根据OpenId自动注册帐户,至此身份认证结束。有时Relying Part须要从Openid Provider那获取该用户的更多信息或资源,OpenId Provider须要对Relying Part的请求进行受权管理,这时就用要到OAuth2.0。ios
OAuth2.0:用户访问受权(Authorization)。OAuth2.0是一个JWT(Json Web Token ,Json格式Web令牌)解决方案。其最终目的是给用户一个包含加密令牌的JSON字符串,这个令牌内包含受权信息,决定了该用户能够访问那些资源。OAuth2.0协议规定了4种取得令牌的方式,能够参考这篇文章OAuth2.0的四种方式。json
Openid Connect:实际上就是将Openid与OAuth2.0结合起来,解决身份认证和身份受权的问题。后端
客户端模式只对客户端进行受权,不涉及到用户信息。若是你的api须要提供到第三方应用,第三方应用本身作用户受权,不须要用到你的用户资源,就能够用客户端模式,只对客户端进行受权访问api资源。api
微软提供了一些针对IdentityServer4的项目模板,在命令行中输入” dotnet new -i IdentityServer4.Templates“便可安装,安装好后能够看到当前已安装的项目模板,其中有一个"is4empty",其实就是一个asp.net core 应用装了IdentityServer4包。在命令行中输入:dotnet new is4empty -n Projectname 就会根据这个模板生成一个新项目。下图是个人项目,一个api客户端、一个mvc客户端,一个identityserver4服务端,其中Api客户端是受保护的Api资源,Mvc客户端是第三方客户端,用于访问被保护的Api客户端,能够当作是任意后端程序。浏览器
public void ConfigureServices(IServiceCollection services) { //添加IdentityServer var builder = services.AddIdentityServer() //身份信息受权资源 .AddInMemoryIdentityResources(Config.GetIdentityResources()) //API访问受权资源 .AddInMemoryApiResources(Config.GetApis()) //添加客户端 .AddInMemoryClients(Config.GetClients()); if (Environment.IsDevelopment()) { builder.AddDeveloperSigningCredential(); } else { throw new Exception("need to configure key material"); } } public void Configure(IApplicationBuilder app) { if (Environment.IsDevelopment()) { app.UseDeveloperExceptionPage(); } //使用IdentityServer中间件 app.UseIdentityServer(); }
为了能更好的查看调试日志,使用窗口调试,能够在Properties/launchSettings.json中能够更改监听地址,默认为5000服务器
启动项目后使用浏览器打开:http://localhost:5000/.well-known/openid-configuration。能够看到identityserver4的discover说明。微信
1,添加ApiResource:修改IdentityServer项目的Config类的GetClients方法,添加一个api资源(ApiResource)。每一个被保护的API项目必需有对应一个ApiResource,一个ApiResource能够有被多个API标识,客户端请求令牌时根据ApiResource名称决定是否有权限访问这个API。mvc
public static IEnumerable<ApiResource> GetApis() { return new ApiResource[] { //secretapi:标识名称,Secret Api:显示名称,能够自定义 new ApiResource("secretapi","Secret Api") }; }
2,添加客户端模式用户:定义好ApiResouce后,再来添加一个客户端,使得这个客户端能够访问secretapi这个资源。修改Config类中的GetClients方法,添加一个用户用于支持客户端模式的请求。app
public static IEnumerable<Client> GetClients() { return new Client[] { new Client() { //客户端Id ClientId="apiClientCd", //客户端密码 ClientSecrets={new Secret("apiSecret".Sha256()) }, //客户端受权类型,ClientCredentials:客户端凭证方式 AllowedGrantTypes=GrantTypes.ClientCredentials, //容许访问的资源 AllowedScopes={ "secretapi" } } }; }
1,配置API项目监听端口和调试方式
2,配置Api项目认证
IdentityApi.Startup.cs
public void ConfigureServices(IServiceCollection services) { services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2); services.AddAuthentication("Bearer").AddJwtBearer(r => { //认证地址 r.Authority = "http://localhost:5000"; //权限标识 r.Audience = "secretapi"; //是否必需HTTPS r.RequireHttpsMetadata = false; }); } // 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(); } else { // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. app.UseHsts(); } app.UseHttpsRedirection(); //使用认证中间件 app.UseAuthentication(); app.UseMvcWithDefaultRoute(); }
3,添加接口:新建一个空的Api控制器(IdentityController),在这个控制器中添加一个Api:GetUserClaims
[ApiController] public class IdentityController : ControllerBase { [HttpGet] [Route("api/identity")] [Microsoft.AspNetCore.Authorization.Authorize] public object GetUserClaims() { return User.Claims.Select(r => new { r.Type, r.Value }); } }
这时GetUserClaims这个Api是访问不了的,用PostMan访问时返回401未认证状态
要访问上面那个受保护的Api,分为2步,第一步从IdentityServer获取token,第二步把这个token使用Bearer authorization 方式添加到Http请求头。
1,在IdentityMvc项目访问受保护的Api
IdentityMvc项目安装一个Nuget包:IdentityModel,这个包对HttpClient对象有扩写,封装了一些IdentityServer的经常使用请求。修改IdentityServer的监听端口为5002,使用窗口调试。
在IdentityMvc的HomeController.cs新增一个控制器GetData
public async Task<IActionResult> GetData() { var client = new HttpClient(); var disco = await client.GetDiscoveryDocumentAsync("http://localhost:5000"); if (disco.IsError) return new JsonResult(new { err=disco.Error}); var token= await client.RequestClientCredentialsTokenAsync(new ClientCredentialsTokenRequest() { //获取Token的地址 Address = disco.TokenEndpoint, //客户端Id ClientId = "apiClientCd", //客户端密码 ClientSecret = "apiSecret", //要访问的api资源 Scope = "secretapi" }); if (token.IsError) return new JsonResult(new { err = token.Error }); client.SetBearerToken(token.AccessToken); string data = await client.GetStringAsync("https://localhost:5001/api/identity"); JArray json = JArray.Parse(data); return new JsonResult(json); }
访问https://localhost:5002/home/getdata能够看到已经成功返回数据
2,使用原生HTTP请求访问受保护的Api
获取access_token:直接打开http://localhost:5000/.well-known/openid-configuration,找到token_endpoint节点
使用PostMan对该节点发送以下Post请求获取access_token
访问被保护的Api
因为使用的是Bearer认证机制,因此添加一个名为Authorization的Http请求头,请求头的内容是字符串“Bearer”+空格+获取到的Token:Bearer Token