今天的内容是受权模式中的简化模式,仍是先看如下受权流程图: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受权模式的过程就进行完了。
扫描二维码关注个人公众号,共同窗习,共同进步!