identityserver4 实现 openid connect 和 oauth 2.0 -尊龙游戏旗舰厅官网
关于 oauth 2.0 的相关内容,点击查看:asp.net webapi owin 实现 oauth 2.0
openid 是一个去中心化的网上身份认证系统。对于支持 openid 的网站,用户不需要记住像用户名和密码这样的传统验证标记。取而代之的是,他们只需要预先在一个作为 openid 身份提供者(identity provider, idp)的网站上注册。openid 是去中心化的,任何网站都可以使用 openid 来作为用户登录的一种方式,任何网站也都可以作为 openid 身份提供者。openid 既解决了问题而又不需要依赖于中心性的网站来确认数字身份。
openid 相关基本术语:
- 最终用户(end user):想要向某个网站表明身份的人。
- 标识(identifier):最终用户用以标识其身份的 url 或 xri。
- 身份提供者(identity provider, idp):提供 openid url 或 xri 注册和验证服务的服务提供者。
- 依赖方(relying party, rp):想要对最终用户的标识进行验证的网站。
以上概念来自:https://zh.wikipedia.org/wiki/openid
针对 .net core 跨平台,微软官方并没有针对 oauth 2.0 的实现(microsoft.aspnetcore.authentication.oauth组件,仅限客户端),identityserver4 实现了 asp.net core 下的 openid connect 和 oauth 2.0,identityserver4 也是微软基金会成员。
阅读目录:
- openid 和 oauth 的区别
- 客户端模式(client credentials)
- 密码模式(resource owner password credentials)
- 简化模式-with openid(implicit grant type)
- 简化模式-with openid & oauth(js 客户端调用)
- 混合模式-with openid & oauth(hybrid flow)
- asp.net core identity and using entityframework core for configuration data
开源地址:https://github.com/yuezhongxin/identityserver4.demo
1. openid 和 oauth 的区别
简单概括:
- openid:authentication(认证),用户是谁?
- oauth:authorization(授权),用户能做什么?
其实,oauth 的密码授权模式和 openid 有些类似,但也不相同,比如用户登录落网选择微博快捷登录方式,大致的区别:
- oauth:用户在微博授权页面输入微博的账号和密码,微博验证成功之后,返回 access_token,然后落网拿到 access_token 之后,再去请求微博的用户 api,微博授权中心验证 access_token,如果验证通过,则返回用户 api 的请求数据给落网。
- openid:落网可以没有用户的任何实现,落网需要确认一个 url 标识(可以是多个),然后用户登录的时候,选择一个 url 进行登录(比如微博),跳转到微博 openid 登录页面,用户输入微博的账号和密码,微博验证成功之后,按照用户的选择,返回用户的一些信息。
可以看到,oauth 首先需要拿到一个授权(access_token),然后再通过这个授权,去资源服务器(具体的 api),获取想要的一些数据,上面示例中,用户 api 只是资源服务器的一种(可以是视频 api、文章 api 等等),在这个过程中,oauth 最重要的就是获取授权(四种模式),获取到授权之后,你就可以通过这个授权,做授权范围之类的任何事了。
而对于 openid 来说,授权和它没任何关系,它只关心的是用户,比如落网,可以不进行用户的任何实现(具体体现就是数据库没有 user 表),然后使用支持 openid 的服务(比如微博),通过特定的 url 标识(可以看作是 openid 标识),然后输入提供服务的账号和密码,返回具体的用户信息,对于落网来说,它关心的是用户信息,仅此而已。
上面其实是 oauth 的授权,所以会有“获得以下权限”提示,如果是 openid 的话,“权限”应该改为“用户信息”。
支持 openid 的服务列表:http://openid.net/get-an-openid/
openid 流程图(来自 using openid):
2. 客户端模式(client credentials)
简单概述:客户端提供 clientid 和 clientsecret 给认证授权服务,验证如果成功,返回 access_token,客户端拿到 access_token,访问 api 资源服务。
2.1 认证授权服务配置
创建 asp.net core 站点,startup 配置修改如下:
public class startup {public void configureservices(iservicecollection services){// configure identity server with in-memory stores, keys, clients and scopesservices.addidentityserver().addtemporarysigningcredential().addinmemoryapiresources(new listidentityserver4 中addinmemory的相关配置,都是 mock 的(代码配置),也可以把这些配置存储在数据库中,这个后面再讲。
addinmemoryapiresources 增加的 api 资源服务(list 集合),也就此认证授权服务所管辖的 api 资源,比如上面配置的 api1,这个会在客户端调用的时候用到,如果不一致,是不允许访问的,另外,clinet 中配置的allowedscopes = { "api1" },表示此种授权模式允许的 api 资源集合(前提是需要添加apiresource)。
配置很简单,我们也可以访问http://localhost:5000/.well-known/openid-configuration,查看具体的配置信息:
2.2 api 资源服务配置
api 资源服务站点,需要添加程序包:
"identityserver4.accesstokenvalidation": "1.0.1"添加一个valuescontroller:
[route("[controller]")] [authorize] public class valuescontroller : controllerbase {[httpget]public iactionresult get(){return content("hello world");} }2.3 单元测试
需要添加程序包:
"identitymodel": "2.0.0"单元测试代码:
[fact] public async task clientcredentials_test() {// request tokenvar disco = await discoveryclient.getasync("http://localhost:5000");var tokenclient = new tokenclient(disco.tokenendpoint, "client", "secret");var tokenresponse = await tokenclient.requestclientcredentialsasync("api1");assert.false(tokenresponse.iserror);console.writeline(tokenresponse.json);// call apivar client = new httpclient();client.setbearertoken(tokenresponse.accesstoken);var response = await client.getasync("http://localhost:5010/values");assert.true(response.issuccessstatuscode);var content = await response.content.readasstringasync();console.writeline(content); }很简单,和我们之前用 asp.net webapi owin 实现 oauth 2.0 一样,只不过配置和调用简化了很多,因为 identityserver4 替我们做了很多工作。
3. 密码模式(resource owner password credentials)
简单概述:客户端提供 username 和 password 给认证授权服务,验证如果成功,返回 access_token,客户端拿到 access_token,访问 api 资源服务。
3.1 认证授权服务配置
创建 asp.net core 站点,startup 配置修改如下:
public class startup {public void configureservices(iservicecollection services){// configure identity server with in-memory stores, keys, clients and scopesservices.addidentityserver().addtemporarysigningcredential().addinmemoryapiresources(new list和客户端模式不同的是,allowedgranttypes授权模式改为了resourceownerpassword,然后增加了测试用户(用来验证用户名和密码),也可以存储在数据库中。
3.2 api 资源服务配置
api 资源服务站点,需要添加程序包:
"identityserver4.accesstokenvalidation": "1.0.1"添加一个identitycontroller:
[route("[controller]")] [authorize] public class identitycontroller : controllerbase {[httpget]public iactionresult get(){return new jsonresult(from c in user.claims select new { c.type, c.value });} }3.3 单元测试
需要添加程序包:
"identitymodel": "2.0.0"单元测试代码:
[fact] public async task resourceownerpassword_test() {// request tokenvar disco = await discoveryclient.getasync("http://localhost:5000");var tokenclient = new tokenclient(disco.tokenendpoint, "ro.client", "secret");var tokenresponse = await tokenclient.requestresourceownerpasswordasync("xishuai", "123", "api1");assert.false(tokenresponse.iserror);console.writeline(tokenresponse.json);// call apivar client = new httpclient();client.setbearertoken(tokenresponse.accesstoken);var response = await client.getasync("http://localhost:5010/identity");assert.true(response.issuccessstatuscode);var content = await response.content.readasstringasync();console.writeline(jarray.parse(content)); }4. 简化模式-with openid(implicit grant type)
简化模式在 identityserver4 中的实现,就是 openid connect。
简单概述:客户端确定 url(用户认证服务),登录在用户认证服务,验证成功,返回客户端想要的用户数据,并使此用户为登录状态,可以在客户端进行注销用户。
4.1 认证授权服务配置
创建 asp.net core 站点,startup 配置修改如下:
public class startup {public void configureservices(iservicecollection services){// configure identity server with in-memory stores, keys, clients and scopesservices.addidentityserver().addtemporarysigningcredential().addinmemoryidentityresources(new listaddinmemoryidentityresources和allowedscopes所配置的,是客户端允许访问的用户信息,具体查看:requesting claims using scope values
clientid 很重要,必须和客户端一一对应,所以想要使用 openid 认证服务的客户端,需要向提供 openid 认证服务的机构,申请一个 clientid,openid 认证服务会统一发放一个用户登录的 url。
testuser中的claims配置,其实就是identityserverconstants.standardscopes.profile。
另外,还有用户登录的一些操作代码,这边就不贴了,可以查看具体的实现:implicitserver.web
4.2 客户端服务配置
创建 asp.net core 站点,添加程序包:
"microsoft.aspnetcore.authentication.cookies": "1.0.*", "microsoft.aspnetcore.authentication.openidconnect": "1.0.*"startup 配置修改如下:
public startup(ihostingenvironment env) {var builder = new configurationbuilder().setbasepath(env.contentrootpath).addjsonfile("appsettings.json", optional: true, reloadonchange: true).addjsonfile($"appsettings.{env.environmentname}.json", optional: true).addenvironmentvariables();configuration = builder.build(); }public iconfigurationroot configuration { get; }public void configureservices(iservicecollection services) {services.addmvc(); }public void configure(iapplicationbuilder app, ihostingenvironment env, iloggerfactory loggerfactory) {jwtsecuritytokenhandler.defaultinboundclaimtypemap.clear();loggerfactory.addconsole(configuration.getsection("logging"));loggerfactory.adddebug();if (env.isdevelopment()){app.usedeveloperexceptionpage();}else{app.useexceptionhandler("/home/error");}app.usecookieauthentication(new cookieauthenticationoptions{authenticationscheme = "cookies"});app.useopenidconnectauthentication(new openidconnectoptions{authenticationscheme = "oidc",signinscheme = "cookies",authority = "http://localhost:5001",requirehttpsmetadata = false,clientid = "mvc",savetokens = true});app.usestaticfiles();app.usemvcwithdefaultroute(); }useopenidconnectauthentication配置中的authority,就是 openid 认证服务的 url。
添加一个homecontroller:
public class homecontroller : controller {public iactionresult index(){return view();}[authorize]public iactionresult secure(){viewdata["message"] = "secure page.";return view();}public async task logout(){await httpcontext.authentication.signoutasync("cookies");await httpcontext.authentication.signoutasync("oidc");}public iactionresult error(){return view();} }访问 secure 页面,跳转到认证服务地址,进行账号密码登录,logout 用于用户的注销操作。
4.3 web 测试
5. 简化模式-with openid & oauth(js 客户端调用)
简单概述:客户端确定 url(用户认证服务),登录在用户认证服务,验证成功,返回客户端想要的用户数据 和 access_token,并使此用户为登录状态,可以在客户端进行注销用户,客户端可以拿到 access_token,去访问授权范围之内的 api 资源。
需要注意的是:因为简化模式,所以 access_token 是作为 url 参数返回的。
5.1 认证授权服务配置
创建 asp.net core 站点,startup 配置修改如下:
public class startup {public void configureservices(iservicecollection services){// configure identity server with in-memory stores, keys, clients and scopesservices.addidentityserver().addtemporarysigningcredential().addinmemoryidentityresources(new list因为涉及到访问 api 资源操作,需要需要添加addinmemoryapiresources配置,allowedscopes也需要添加对应的 api 资源名称,allowaccesstokensviabrowser = true的配置的作用就是,可以在浏览器地址中访问 access_token。
更多实现代码,点击查看:implicitserverwithjs.web
5.2 api 资源服务配置
api 资源服务站点,需要添加程序包:
"identityserver4.accesstokenvalidation": "1.0.1", "microsoft.aspnetcore.cors": "1.1.0"startup 配置修改如下:
public startup(ihostingenvironment env) {var builder = new configurationbuilder().setbasepath(env.contentrootpath).addjsonfile("appsettings.json", optional: true, reloadonchange: true).addjsonfile($"appsettings.{env.environmentname}.json", optional: true);builder.addenvironmentvariables();configuration = builder.build(); }public iconfigurationroot configuration { get; }public void configureservices(iservicecollection services) {services.addcors(options =>{// this defines a cors policy called "default"options.addpolicy("default", policy =>{policy.withorigins("http://localhost:5022").allowanyheader().allowanymethod();});});services.addmvccore().addauthorization().addjsonformatters(); }public void configure(iapplicationbuilder app, iloggerfactory loggerfactory) {loggerfactory.addconsole(configuration.getsection("logging"));loggerfactory.adddebug();app.usecors("default");app.useidentityserverauthentication(new identityserverauthenticationoptions{authority = "http://localhost:5003",requirehttpsmetadata = false,apiname = "api1"});app.usemvc(); }因为 js 需要跨域访问 api 资源服务,所以需要增加 cors 配置。
添加一个identitycontroller:
[route("[controller]")] [authorize] public class identitycontroller : controllerbase {[httpget]public iactionresult get(){return new jsonresult(from c in user.claims select new { c.type, c.value });} }5.3 js web 站点测试
创建一个 asp.net core 站点,添加oidc-client.js前端组件,测试 js 代码:
///测试过程(注意下 url 中的参数):
6. 混合模式-with openid & oauth(hybrid flow)
混合模式(hybrid flow)是一种新的模式,是简化模式(implicit flow)和验证码模式(authorization code flow)的混合。
简单概述:客户端确定 url(用户认证服务),登录在用户认证服务,验证成功,返回客户端想要的用户数据 和 access_token,并使此用户为登录状态,可以在客户端进行注销用户,客户端可以拿到 access_token,去访问授权范围之内的 api 资源。
和上面的简化模式流程差不多,不过 access_token 不是通过浏览器获取的,而是通过后台服务获取。
6.1 认证授权服务配置
创建 asp.net core 站点,startup 配置修改如下:
public class startup {public void configureservices(iservicecollection services){// configure identity server with in-memory stores, keys, clients and scopesservices.addidentityserver().addtemporarysigningcredential().addinmemoryidentityresources(new listallowedgranttypes配置改为hybridandclientcredentials,allowofflineaccess需要设置为true。
更多实现代码,点击查看:hybridserver.web
6.2 api 资源服务配置
api 资源服务站点,需要添加程序包:
"identityserver4.accesstokenvalidation": "1.0.1"startup 配置修改如下:
public startup(ihostingenvironment env) {var builder = new configurationbuilder().setbasepath(env.contentrootpath).addjsonfile("appsettings.json", optional: true, reloadonchange: true).addjsonfile($"appsettings.{env.environmentname}.json", optional: true);builder.addenvironmentvariables();configuration = builder.build(); }public iconfigurationroot configuration { get; }public void configureservices(iservicecollection services) {services.addmvccore().addauthorization().addjsonformatters(); }public void configure(iapplicationbuilder app, iloggerfactory loggerfactory) {loggerfactory.addconsole(configuration.getsection("logging"));loggerfactory.adddebug();app.useidentityserverauthentication(new identityserverauthenticationoptions{authority = "http://localhost:5002",requirehttpsmetadata = false,apiname = "api1"});app.usemvc(); }添加一个identitycontroller:
[route("[controller]")] [authorize] public class identitycontroller : controllerbase {[httpget]public iactionresult get(){return new jsonresult(from c in user.claims select new { c.type, c.value });} }6.3 客户端服务配置
创建 asp.net core 站点,添加程序包:
"microsoft.aspnetcore.authentication.cookies": "1.0.*", "microsoft.aspnetcore.authentication.openidconnect": "1.0.*", "identitymodel": "2.0.0"startup 配置修改如下:
public startup(ihostingenvironment env) {var builder = new configurationbuilder().setbasepath(env.contentrootpath).addjsonfile("appsettings.json", optional: true, reloadonchange: true).addjsonfile($"appsettings.{env.environmentname}.json", optional: true).addenvironmentvariables();configuration = builder.build(); }public iconfigurationroot configuration { get; }public void configureservices(iservicecollection services) {services.addmvc(); }public void configure(iapplicationbuilder app, ihostingenvironment env, iloggerfactory loggerfactory) {jwtsecuritytokenhandler.defaultinboundclaimtypemap.clear();loggerfactory.addconsole(configuration.getsection("logging"));loggerfactory.adddebug();if (env.isdevelopment()){app.usedeveloperexceptionpage();}else{app.useexceptionhandler("/home/error");}app.usecookieauthentication(new cookieauthenticationoptions{authenticationscheme = "cookies"});app.useopenidconnectauthentication(new openidconnectoptions{authenticationscheme = "oidc",signinscheme = "cookies",authority = "http://localhost:5002",requirehttpsmetadata = false,clientid = "mvc",clientsecret = "secret",responsetype = "code id_token",scope = { "api1", "offline_access" },getclaimsfromuserinfoendpoint = true,savetokens = true});app.usestaticfiles();app.usemvcwithdefaultroute(); }添加一个homecontroller:
public class homecontroller : controller {public iactionresult index(){return view();}[authorize]public iactionresult secure(){viewdata["message"] = "secure page.";return view();}public async task logout(){await httpcontext.authentication.signoutasync("cookies");await httpcontext.authentication.signoutasync("oidc");}public iactionresult error(){return view();}public async taskcallapiusingclientcredentials是通过客户端模式获取 access_token,callapiusinguseraccesstoken是通过上下文获取保存的 access_token,其实和浏览器 url 中获取是一样的意思,但需要配置savetokens = true。
6.4 web 测试
7. asp.net core identity and using entityframework core for configuration data
使用 asp.net core identity,就是用户管理不由 openid 认证服务进行提供,asp.net core identity 就相当于用户的一个管理者,比如用户的存储等。
我没做这一块的示例,配置比较简单:
public void configureservices(iservicecollection services) {services.adddbcontext详细使用:using asp.net core identity
关于 identityserver4 的配置信息,可以使用 entityframework core 进行存储,配置如下:
public void configureservices(iservicecollection services) {services.addmvc();var connectionstring = @"server=(localdb)\mssqllocaldb;database=identityserver4.quickstart;trusted_connection=yes";var migrationsassembly = typeof(startup).gettypeinfo().assembly.getname().name;// configure identity server with in-memory users, but ef stores for clients and resourcesservices.addidentityserver().addtemporarysigningcredential().addtestusers(config.getusers()).addconfigurationstore(builder =>builder.usesqlserver(connectionstring, options =>options.migrationsassembly(migrationsassembly))).addoperationalstore(builder =>builder.usesqlserver(connectionstring, options =>options.migrationsassembly(migrationsassembly))); }详细使用:using entityframework core for configuration data
最后,简要总结下使用 identityserver4 的几种应用场景:
- 客户端模式(client credentials):和用户无关,用于应用程序与 api 资源的直接交互场景。
- 密码模式(resource owner password credentials):和用户有关,一般用于第三方登录。
- 简化模式-with openid(implicit grant type):仅限 openid 认证服务,用于第三方用户登录及获取用户信息,不包含授权。
- 简化模式-with openid & oauth(js 客户端调用):包含 openid 认证服务和 oauth 授权,但只针对 js 调用(url 参数获取),一般用于前端或无线端。
- 混合模式-with openid & oauth(hybrid flow):推荐使用,包含 openid 认证服务和 oauth 授权,但针对的是后端服务调用。
开源地址:https://github.com/yuezhongxin/identityserver4.demo
参考资料:
- identityserver4
- identityserver4.samples
- welcome to identityserver4
- welcome to openid connect
- openid 学习笔记
- oauth 和 openid 的区别
- oauth、oauth 与 openid 区别和联系
- 使用 openid、oauth 和 facebook connect 武装你的站点
- openid connect 身份认证标准推出,获谷歌微软支持
总结
以上是尊龙游戏旗舰厅官网为你收集整理的identityserver4 实现 openid connect 和 oauth 2.0的全部内容,希望文章能够帮你解决所遇到的问题。
- 上一篇: 【设计模式】责任者模式
- 下一篇: