今天的內容是受權模式中的簡化模式,仍是先看如下受權流程圖:git
在這種模式中咱們將與OpenID結合使用,因此首先咱們要了解OpenID和OAuth的區別,關於他們的區別,在我上一篇博客《理解OpenID和OAuth的區別》中作了的一些簡要的介紹,這裏再也不多說。github
受權服務器咱們仍是在以前的基礎上改動,首先咱們須要在Config類裏面添加對OpenID Connect Identity Scopes的支持,與OAuth2.0相比,OIDC(OpenID Connect)一樣須要Scopes的概念,他也須要保護Scopes範圍的內容而也須要讓用戶去訪問的內容,可是OIDC中這裏的範圍並非用戶要訪問的API,而是用戶標識、用戶名、Email等信息。bash
添加對OpenId(SubjectId) Profile(first name last name etc...)的支持範圍,並返回一個IdentityReSource的集合,添加如下代碼:服務器
//添加對OpenID Profile範圍的支持 public static IEnumerable<IdentityResource> GetIdentityResources() { return new List<IdentityResource>{ new IdentityResources.OpenId(), new IdentityResources.Profile(), }; }
再天際一個客戶端,基於Implicit受權模式,添加如下代碼:app
new Client(){ ClientId="impClient", AllowedGrantTypes=GrantTypes.Implicit, //用於登陸成功後的RedirectUri RedirectUris={"http://localhost:5004/signin-oidc"}, //用於註銷後的RedirectUri PostLogoutRedirectUris={"http://localhost:5004/signout-callback-oidc"}, //容許訪問的範圍 AllowedScopes={ IdentityServerConstants.StandardScopes.OpenId, IdentityServerConstants.StandardScopes.Profile } }
下面咱們還要將IdentityResource注入到IdentityServer中,在ConfigureService中,添加:curl
.AddInMemoryIdentityResources(Config.GetIdentityResources())async
修改返回的TestUser的方法,在每個用戶中添加一個聲明屬性的集合,返回一個name和address信息,改動以下:學習
return new List<TestUser>{ new TestUser(){ SubjectId="1", Username="allen", Password="123456", Claims=new List<Claim> { new Claim("name","Allen"), new Claim("address","http://allen.com") } }, new TestUser(){ SubjectId="2", Username="alisa", Password="123456", Claims=new List<Claim> { new Claim("name","Alisa"), new Claim("address","http://alisa.com") } }
OIDC所需的全部協議已經內置在IdentityServer4中了,須要爲登陸、註銷、贊成受權內容以及錯誤等提供UI的部分,IdentityServer4提供了一個簡單的基於MVC的UI界面,咱們能夠直接download到咱們的服務端裏,在控制檯使用命令:ui
若是你是Windows系統,使用如下命令:this
iex ((New-Object System.Net.WebClient).DownloadString('https://raw.githubusercontent.com/IdentityServer/IdentityServer4.Quickstart.UI/release/get.ps1'))
若是你是MacOS或者Linux用戶,使用:
\curl -L https://raw.githubusercontent.com/IdentityServer/IdentityServer4.Quickstart.UI/release/get.sh | bash
執行完成後,會發現多了一個QuickStart文件夾,放置了所用到的Controller,Views文件夾下也放置了對應的視圖,
因爲我建立的是WebApi項目,因此還要在StartUp.cs裏面將原來咱們註釋掉的app.UseMvc()解開,另外在配置默認路由前還要添加使用靜態文件,以使用咱們的靜態文件夾下的樣式,app.UseStaticFiles(); 以上內容都修改完成後,下面咱們新建一個Mvc的項目,去請求咱們的受權服務器,如何建立再也不贅述,建立完成後添加對OIDC認證的支持,在ConfigureServices的方法中添加如下代碼:
using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using System.IdentityModel.Tokens.Jwt; namespace MvcClient { public class Startup { public Startup(IConfiguration configuration) { Configuration = configuration; } public IConfiguration Configuration { get; } // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear(); //添加認證服務到DI中, services.AddAuthentication(options=>{ //使用Cookies做爲惟一的認證用戶的主要手段 options.DefaultScheme="Cookies"; //須要用戶登陸纔可進入該應用程序,使用OpenID Connect scheme options.DefaultChallengeScheme="oidc"; }) //添加能夠處理Cookie的處理程序 .AddCookie("Cookies") //配置OpenID Connect協議 .AddOpenIdConnect("oidc",options=>{ //OIDC協議執行完成,發佈Cookie options.SignInScheme="Cookies"; //受權服務器地址 options.Authority="http://localhost:5000"; options.RequireHttpsMetadata=false; //指定客戶端Id options.ClientId="impClient"; //保存令牌在Cookie中 options.SaveTokens=true; }); services.AddMvc(); } // 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 { app.UseExceptionHandler("/Home/Error"); } app.UseStaticFiles(); //添加認證中間件 app.UseAuthentication(); app.UseMvc(routes => { routes.MapRoute( name: "default", template: "{controller=Home}/{action=Index}/{id?}"); }); } } }
注意配置啓動時將MvcClient啓動端口改成5004,由於我在服務端指定的客戶端的端口爲5004,接着咱們添加一個Action,使他須要進行受權訪問,
[Authorize] public IActionResult Authorize() { return View(); }
並添加對應的視圖,展現用戶信息:
@{ ViewData["Title"] = "Authorize"; } <h2>Claims:</h2> <dl> @foreach (var claim in User.Claims) { <dt>@claim.Type</dt> <dd>@claim.Value</dd> } </dl>
至此,咱們的配置就完成了,下面咱們運行看下效果,首先run下服務端,再啓動咱們的客戶端,客戶端點擊Authorize菜單:
這個就對應咱們那個須要QQ登陸的界面了,須要經過認證,咱們輸入咱們事先配置的用戶名和密碼,allen 123456,
到consent頁面是要經過咱們的受權,將咱們用戶信息共享給客戶端,如今咱們選擇用戶profile,點擊容許:
當咱們點擊不容許讀取用戶信息的時候:
在不容許讀取的狀況下,咱們是沒法看到用戶名的。下面咱們再添加一個註銷登陸的方法,
//註銷登陸 public async Task LogOut() { await HttpContext.SignOutAsync("Cookies"); await HttpContext.SignOutAsync("oidc"); }
執行退出:
至此整個Implicit受權模式的過程就進行完了。
掃描二維碼關注個人公衆號,共同窗習,共同進步!