IdentityServer4是一套身份受權以及訪問控制的解決方案,專一於幫助使用.Net 技術的公司爲現代應用程序創建標識和訪問控制解決方案,包括單點登陸、身份管理、受權和API安全。api
下面我將具體介紹如何在.Net Core中實現OAuth受權,從最簡單的受權模式開始,在上一篇對OAuth2.0的詳細描述中,在客戶端模式中,咱們說它在嚴格意義上講是不存在受權的問題,咱們再來看下它的受權流程:安全
客戶端在向受權服務器申請令牌後,受權服務器直接將令牌返回給了客戶端,這個過程不須要其餘角色的任何操做,只是客戶端和受權服務器的交互。咱們結合具體的示例來進一步瞭解這個過程。服務器
操做系統:Mac OSsession
開發工具:VS Codemvc
調試工具:Postmanapp
開發框架:.Net Core 2.0框架
在具體示例實現以前,先說一下在VS Code咱們會用到的插件,以方便咱們的開發,畢竟VS Code沒有咱們宇宙第一IDE-Visual Studio那麼強大,可是也是目前爲止最好用的編輯器,它提供了各式各樣的插件,幾乎知足咱們全部的開發需求。在這裏咱們用到的一個插件叫作Nuget Package Manager,這個插件能夠方便咱們使用快捷鍵對Nuget包進行管理。編輯器
接下來咱們首先建立一個受權服務器的項目,打開VS Code使用控制檯,建立一個WebApi的項目,使用命令:工具
dotnet new WebApi -n IdentityServer4.Server
建立完成後,咱們能夠啓動查看咱們的項目,run一下:post
這樣咱們的項目是能夠運行成功的,下面咱們進行添加IdentitServer4包的引用,在咱們安裝了Nuget Package Manager後,咱們能夠快速的使用快捷鍵,在Mac系統中使用command+p,而後輸入">",而後輸入Nuget... (注意必定要切換到當前的項目下)會出現如下提示:
選擇第一個選項添加Package:
按回車,選擇IdentityServer4最新版本的安裝,這裏是2.1.3,安裝完後,咱們在StartUp中添加IdentityServer4的引用,並使用AddIdentityServer()方法在依賴注入系統中註冊IdentityServer,固然這裏咱們也能夠等到添加完配置類後再進行操做。咱們先添加一個配置類,叫作Config.cs,首先定義一個管道(Scope),指定咱們所保護Api資源,該方法返回一個ApiResources集合,具體代碼以下:new ApiResource("api","UsersApi"),第一個參數爲Api的名稱,第二個參數爲顯示的名稱:
下一步進行客戶端註冊,定義給客戶端能夠返回的資源,即容許哪一個Scope定義,代碼以下:
下面咱們將該配置注入到系統中,
AddDeveloperSigningCredential(),是一種RSA證書加密方式,它會生成一個tempkey.rsa證書文件,項目每次啓動時,會檢查項目根目錄是否存在該證書文件,若不存在,則會生成該文件,不然會繼續使用該證書文件。後面依次將ApiResources和Clients添加到內存中。
下一步是配置IdentityServer4的管道,在Configure裏面添加,app.UseIdentityServer(),在這裏咱們用不到mvc,將app.UseMvc()註釋掉便可。下面咱們運行咱們的項目,固然直接訪問http://localhost:5000是看不到任何東西的,在這裏咱們使用一個固定的地址http://localhost:5000/.well-known/openid-configuration,能夠查看IdentityServer4的配置信息,運行格式化後內容以下:
{ "issuer": "http://localhost:5000", "jwks_uri": "http://localhost:5000/.well-known/openid-configuration/jwks", "authorization_endpoint": "http://localhost:5000/connect/authorize", "token_endpoint": "http://localhost:5000/connect/token", "userinfo_endpoint": "http://localhost:5000/connect/userinfo", "end_session_endpoint": "http://localhost:5000/connect/endsession", "check_session_iframe": "http://localhost:5000/connect/checksession", "revocation_endpoint": "http://localhost:5000/connect/revocation", "introspection_endpoint": "http://localhost:5000/connect/introspect", "frontchannel_logout_supported": true, "frontchannel_logout_session_supported": true, "backchannel_logout_supported": true, "backchannel_logout_session_supported": true, "scopes_supported": [ "api", "offline_access" ], "claims_supported": [], "grant_types_supported": [ "authorization_code", "client_credentials", "refresh_token", "implicit" ], "response_types_supported": [ "code", "token", "id_token", "id_token token", "code id_token", "code token", "code id_token token" ], "response_modes_supported": [ "form_post", "query", "fragment" ], "token_endpoint_auth_methods_supported": [ "client_secret_basic", "client_secret_post" ], "subject_types_supported": [ "public" ], "id_token_signing_alg_values_supported": [ "RS256" ], "code_challenge_methods_supported": [ "plain", "S256" ] }
上面指定的3個參數都是客戶端模式須要指定的參數,下面就是咱們請求到的access token。接着咱們建立一個Api,去調用咱們的受權服務器進行受權,重複上面的步驟,建立一個WebApi項目,再也不贅述,直接去配置調用受權服務器,這個項目只是一個Api的項目,不須要完整的IdentityServer4的引用,只引用一個IdentityServer4.AccessTokenValidation包就能夠了。在受權服務器中咱們已經佔用5000端口,因此在這個項目中咱們指定爲5001端口,在Program.cs裏面指定5001端口,添加.UseUrls("http://localhost:5001"):
在ValuesController裏面添加 Microsoft.AspNetCore.Authorization的引用,並添加[Authorize]標籤,即要求該Controller要經過受權才能夠訪問,
下面咱們在StartUp.cs裏面去配置受權服務:
接着咱們分別啓動受權服務器和Api,咱們運行Api,訪問:http://localhost:5001/api/values ,訪問結果以下:
提示Http Error 401 ,在狀態碼中401即未受權,咱們把它拿到Postman中運行:
咱們在Headers中指定Authorization 模式爲Bearer,狀態401 未受權,這個結果也是咱們意料中的結果了,由於咱們並未獲取到令牌,咱們繼續使用Postman模擬獲取到access token,
咱們將獲取到的access_token放到Api的Headers裏面:
注意令牌與Bearer中間加空格,接下來繼續請求:
這樣咱們就拿到了Api裏面要獲取的值了,到這裏咱們使用Postman驗證了咱們的結果,下面咱們再建立一個第三方應用,去請求咱們的Api資源,繼續瞭解咱們的受權流程,客戶端我使用控制檯程序進行測試。
咱們繼續使用命令行建立第三方應用,名稱爲ThirdPartyApplication,IdentityServer4有一個專門專門爲客戶端程序用的Nuget包,叫作IdentityModel,咱們仍是經過快捷鍵添加Nuget Package,下面直接上代碼,必要說明會在代碼中直接註釋:
using System; using System.Net.Http; using IdentityModel; using IdentityModel.Client; namespace ThirdPartyApplication { class Program { static void Main(string[] args) { //請求受權服務器 var diso=DiscoveryClient.GetAsync("http://localhost:5000").Result; if(diso.IsError) { Console.WriteLine(diso.Error); } //受權服務器根據客戶端發來的請求返回令牌 var tokenClient=new TokenClient(diso.TokenEndpoint,"Client","secret"); var tokenResponse=tokenClient.RequestClientCredentialsAsync("api").Result; if(tokenResponse.IsError) { Console.WriteLine(tokenResponse.Error); } //若是成功,則打印輸出返回的令牌信息 else { Console.WriteLine(tokenResponse.Json); } //建立HttpClient對象 var httpClient=new HttpClient(); //設置Authorization的Value值 httpClient.SetBearerToken(tokenResponse.AccessToken); //根據受權服務器返回的令牌信息請求Api資源 var response= httpClient.GetAsync("http://localhost:5001/api/values").Result; //若是返回結果爲成功,輸出Api資源的結果 if(response.IsSuccessStatusCode) { Console.WriteLine(response.Content.ReadAsStringAsync().Result); } } } }
下面輸出結果:
以上就是咱們整個OAuth2.0受權模式中完整的客戶端受權模式了,以上流程簡化以下:
後面文章會繼續講解其餘幾種受權模式的使用。各位,晚安。
掃描二維碼關注個人公衆號,共同窗習,共同進步!