本博客根據http://video.jessetalk.cn/my/course/5視頻整理html
OAuth2 流程:http://www.ruanyifeng.com/blog/2014/05/oauth_2_0.htmlgit
博客園曉晨的關於identityServer4的中文文檔地址: http://www.cnblogs.com/stulzq/p/8119928.htmlweb
Docker中文文檔 https://yeasy.gitbooks.io/docker_practice/content/docker
OAuth2.0(Open Authorization)是一個開放受權協議;第三方應用不須要接觸到用戶的帳戶信息(如用戶名密碼),經過用戶的受權訪問用戶資源json
OAuth的步驟通常以下:api
一、客戶端要求用戶給予受權
二、用戶贊成給予受權
三、根據上一步得到的受權,向認證服務器請求令牌(token)
四、認證服務器對受權進行認證,確認無誤後發放令牌
五、客戶端使用令牌向資源服務器請求資源
六、資源服務器使用令牌向認證服務器確認令牌的正確性,確認無誤後提供資源服務器
該協議的參與者至少包含:restful
RO (resource owner): 資源全部者:用戶。app
RS (resource server): 資源服務器:數據中心;它存儲資源,並處理對資源的訪問請求。如:API資源,相冊服務器、博客服務器。ide
AS (authorization server): 受權服務器
Client: 第三方應用
四種模式:
一、受權碼模式(authorization code)
二、簡化模式(implicit)
三、密碼模式(resource owner password credentials)
四、客戶端模式(client credentials)
接下來咱們使用客戶端模式來實現一個IdentityServer4受權
客戶端模式(ClientCredentials):常常運用於服務器對服務器中間通信使用;步驟以下:
一、客戶端直接用自身的信息向受權服務器請求token:
HTTP請求:
granttype:受權類型
scope:受權範圍
POST /token HTTP/1.1 Host: server.example.com Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW Content-Type: application/x-www-form-urlencoded grant_type=client_credentials&scope=api001
二、受權服務器驗證信息後返回token
HTTP/1.1 200 OK Content-Type: application/json;charset=UTF-8 Cache-Control: no-store Pragma: no-cache { "access_token":"2YotnFZFEjr1zCsicMWpAA", "token_type":"example", "expires_in":3600, "example_parameter":"example_value" }
下面經過一個快速示例理解;快速示例將經過服務器與服務器直接經過api訪問數據;
步驟:
添加Nuget包:IdentityServer4
添加Startup配置
添加Config.cs配置類
更改identity server4配置
添加客戶端配置
首先,新建一個webapi項目 IdentityServerCenter
dotnet new webapi --name IdentityServerCenter
咱們能夠在vscode中使用ctrl+P鍵來打開命令面板。而後輸入nuget按回車,輸入identityserver4後按回車來選擇版本進行安裝
【注意:從新打開文件夾項目後才能在類中引用IdentityServer4有提示】
引用命名空間:
using IdentityServer4;
添加IdentityServer依賴注入
services.AddIdentityServer() .AddDeveloperSigningCredential();//添加開發人員簽名憑據
app.UseIdentityServer();//使用IdentityServer
咱們能夠在Program.cs將當前api的地址設置成http://localhost:5000
咱們接下來添加一個Config.cs類,這個類是用來初始化IdentityServer的
using System.Collections; using System.Collections.Generic; using IdentityServer4; using IdentityServer4.Models; namespace IdentityServerCenter { public class Config { //全部能夠訪問的Resource public static IEnumerable<ApiResource> GetResources() { return new List<ApiResource> { new ApiResource("api","My Api") }; } //客戶端 public static IEnumerable<Client> GetClients() { return new List<Client> { new Client() { ClientId="client", AllowedGrantTypes= GrantTypes.ClientCredentials,//模式:最簡單的模式 ClientSecrets={//私鑰 new Secret("secret".Sha256()) }, AllowedScopes={//能夠訪問的Resource "api" } } }; } } }
services.AddIdentityServer() .AddDeveloperSigningCredential()//添加開發人員簽名憑據 .AddInMemoryApiResources(Config.GetResources());//添加內存apiresource
services.AddIdentityServer() .AddDeveloperSigningCredential()//添加開發人員簽名憑據 .AddInMemoryApiResources(Config.GetResources())//添加內存apiresource .AddInMemoryClients(Config.GetClients());//添加內存client
這是後咱們執行dotnet run經過http://localhost:5000/.well-known/openid-configuration訪問 ;能夠看到是一個restful的api;
新建一個新的webapi,命名爲ClientCredentialApi
dotnet new webapi --name ClientCredentialApi
給控制器添加引用Microsoft.AspNetCore.Authorization並添加 [Authorize] 標籤
添加中間件IdentityServer4.AccessTokenValidation 包引用
配置api的地址 http://localhost:5001
添加受權DI注入
services.AddAuthentication("Bearer")//添加受權模式 .AddIdentityServerAuthentication(Options=>{ Options.Authority="http://localhost:5000";//受權服務器地址 Options.RequireHttpsMetadata=false;//是不是https Options.ApiName="api"; });
app.UseAuthentication();//使用受權中間件
這時候執行 dotnet run進行訪問http://localhost:5001/api/values
這時候咱們運行以前的IdentityServerCenter經過http://localhost:5000/.well-known/openid-configuration訪問 ,來拿到獲取token的地址 http://localhost:5000/connect/token
咱們接下來使用postman來獲取一下token,請求參數
client_id、client_secret、grant_type
這樣咱們拿到token後,再去訪問ClientCredentialApi(成功)
新建一個控制檯ThirdPartyDemo
dotnet new console --name ThirdPartyDemo
添加添加nuget引用包 IdentityModel
using System; using System.Net.Http; using IdentityModel.Client; namespace ThirdPartyDemo { class Program { static void Main(string[] args) { var dico = DiscoveryClient.GetAsync("http://localhost:5000").Result; //token var tokenClient = new TokenClient(dico.TokenEndpoint, "client", "secret"); var tokenResponse = tokenClient.RequestClientCredentialsAsync("api").Result; if (tokenResponse.IsError) { Console.WriteLine(tokenResponse.Error); return; } Console.WriteLine(tokenResponse.Json); Console.WriteLine("\n\n"); var httpClient = new HttpClient(); httpClient.SetBearerToken(tokenResponse.AccessToken); var response = httpClient.GetAsync("http://localhost:5001/api/values").Result; if (!response.IsSuccessStatusCode) { Console.WriteLine(response.Content.ReadAsStringAsync().Result); } Console.ReadLine(); } } }
DiscoveryClient類:IdentityModel提供給咱們經過基礎地址(如:http://localhost:5000)就能夠訪問令牌服務端;固然能夠根據上面的restful api裏面的url自行構建;上面就是經過基礎地址,獲取一個TokenClient;(對應restful的url:token_endpoint "http://localhost:5000/connect/token")
RequestClientCredentialsAsync方法:請求令牌;
獲取令牌後,就能夠經過構建http請求訪問API接口;這裏使用HttpClient構建請求,獲取內容;
運行效果:
一、Config.cs添加用戶的配置
二、添加client的配置
三、修改Startup.cs
添加測試用戶,並給其用戶名密碼(其餘Claim);TestUser是IdentityServer給咱們的測試抽象用戶類;實際可自行定義
TestUser
類型表示一個測試用戶及其身份信息。讓咱們向配置類(若是你有嚴格按照順序進行演練,那麼配置類應該在 QuickstartIdentityServer 項目的 Config.cs 文件中)中添加如下代碼以建立一對用戶:
首先添加如下語句 到Config.cs
文件中:
//測試用戶 public static List<TestUser> GetTestUsers() { return new List<TestUser>{ new TestUser{ SubjectId="1", Username="wyt", Password="123456" } }; }
添加一個客戶端
這裏AddTestUser會給受權服務端增長各種支持用戶(RO)的密碼支持
咱們接下來使用postman來獲取一下帳號密碼模式token,請求參數【注意:這裏必需要使用x-www-form-urlencoded的請求方式,不然沒法獲取token】
client_id、client_secret、grant_type、username、password
完成~~~
新建一個控制檯PwdClient
dotnet new console --name PwdClient
添加添加nuget引用包 IdentityModel
using System; using System.Net.Http; using IdentityModel.Client; namespace PwdClient { class Program { static void Main(string[] args) { var dico = DiscoveryClient.GetAsync("http://localhost:5000").Result; //token var tokenClient = new TokenClient(dico.TokenEndpoint, "pwdClient", "secret"); var tokenResponse = tokenClient.RequestResourceOwnerPasswordAsync("wyt","123456").Result; if (tokenResponse.IsError) { Console.WriteLine(tokenResponse.Error); return; } Console.WriteLine(tokenResponse.Json); Console.WriteLine("\n\n"); var httpClient = new HttpClient(); httpClient.SetBearerToken(tokenResponse.AccessToken); var response = httpClient.GetAsync("http://localhost:5001/api/values").Result; if (!response.IsSuccessStatusCode) { Console.WriteLine(response.Content.ReadAsStringAsync().Result); } Console.ReadLine(); } } }
運行效果:
若是信任的第三方,不想加入密碼,能夠在受權服務的Config.cs中Client添加設置RequireClientSecret=false便可