本博客根據http://video.jessetalk.cn/my/course/5視頻整理
資料
OAuth2 流程:http://www.ruanyifeng.com/blog/2014/05/oauth_2_0.html
博客園曉晨的關於identityServer4的中文文檔地址: http://www.cnblogs.com/stulzq/p/8119928.html
Docker中文文檔 https://yeasy.gitbooks.io/docker_practice/content/
OAuth2.0概念
OAuth2.0(Open Authorization)是一個開放授權協議;第三方應用不需要接觸到用戶的賬戶信息(如用戶名密碼),通過用戶的授權訪問用戶資源
OAuth的步驟一般如下:
1、客戶端要求用戶給予授權
2、用戶同意給予授權
3、根據上一步獲得的授權,向認證服務器請求令牌(token)
4、認證服務器對授權進行認證,確認無誤后發放令牌
5、客戶端使用令牌向資源服務器請求資源
6、資源服務器使用令牌向認證服務器確認令牌的正確性,確認無誤后提供資源
該協議的參與者至少包含:
RO (resource owner): 資源所有者:用戶。
RS (resource server): 資源服務器:數據中心;它存儲資源,並處理對資源的訪問請求。如:API資源,相冊服務器、博客服務器。
AS (authorization server): 授權服務器
Client: 第三方應用
四種模式:
1、授權碼模式(authorization code)
2、簡化模式(implicit)
3、密碼模式(resource owner password credentials)
4、客戶端模式(client credentials)
接下來我們使用客戶端模式來實現一個IdentityServer4授權
客戶端模式(Client Credentials Grant)
客戶端模式(ClientCredentials):經常運用於服務器對服務器中間通訊使用;步驟如下:
1、客戶端直接用自身的信息向授權服務器請求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
2、授權服務器驗證信息后返回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配置
添加客戶端配置
第一步:添加Nuget包:IdentityServer4
首先,新建一個webapi項目 IdentityServerCenter
dotnet new webapi --name IdentityServerCenter
我們可以在vscode中使用ctrl+P鍵來打開命令面板。然后輸入nuget按回車,輸入identityserver4后按回車來選擇版本進行安裝
【注意:重新打開文件夾項目后才能在類中引用IdentityServer4有提示】
第二步:添加Startup配置
引用命名空間:
using IdentityServer4;
添加IdentityServer依賴注入
services.AddIdentityServer() .AddDeveloperSigningCredential();//添加開發人員簽名憑據
app.UseIdentityServer();//使用IdentityServer
我們可以在Program.cs將當前api的地址設置成http://localhost:5000
第三步:添加Config.cs配置類
我們接下來添加一個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" } } }; } } }
第四步:更改identity server4配置
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;
客戶端集成IdentityServer
新建一個新的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(成功)
控制台獲取token
新建一個控制台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構建請求,獲取內容;
運行效果:
oauth密碼模式identity server4實現
1、Config.cs添加用戶的配置
2、添加client的配置
3、修改Startup.cs
Config.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" } }; }
添加client的配置
添加一個客戶端
修改Startup.cs
這里AddTestUser會給授權服務端增加各類支持用戶(RO)的密碼支持
我們接下來使用postman來獲取一下賬號密碼模式token,請求參數【注意:這里必須要使用x-www-form-urlencoded的請求方式,否則無法獲取token】
client_id、client_secret、grant_type、username、password
完成~~~
控制台請求獲取token
新建一個控制台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即可