系列导航
SpringSecurity系列
SpringSecurityOauth2系列初认Oauth2
hello!我⼜来啦!
之前我们学习了前后端分离的SpringSecurity架构,但是在微服务满天飞的今天,前⾯学习的这种架构已经不适⽤了。诶那么有没有⼀种适⽤于微服务的安全框架呢?当然就是SpringSecurityOauth2了。
有的⼩伙伴⼀看,这不还是SpringSecurity嘛,后⾯加了⼀个Oauth2后缀,啥是Oauth2啊?别急,我们先来看看Oauth2的概念Oauth2的概念
先说OAuth,OAuth是Open Authorization的简写。
OAuth协议为⽤户资源的授权提供了⼀个安全的、开放⽽⼜简易的标准。与以往的授权⽅式不同之处是OAuth的授权不会使第三⽅触及到⽤户的帐号信息(如⽤户名与密码),即第三⽅⽆需使⽤⽤户的⽤户名与密码就可以申请获得该⽤户资源的授权,因此OAuth是安全的。
OAuth2.0是OAuth协议的延续版本,但不向前兼容(即完全废⽌了OAuth1.0)。使⽤场景
假设,A⽹站是⼀个打印照⽚的⽹站,B⽹站是⼀个存储照⽚的⽹站,⼆者原本毫⽆关联。
如果⼀个⽤户想使⽤A⽹站打印⾃⼰存储在B⽹站的照⽚,那么A⽹站就需要使⽤B⽹站的照⽚资源才⾏。
按照传统的思考模式,我们需要A⽹站具有登录B⽹站的⽤户名和密码才⾏,但是,现在有了OAuth2,只需要A⽹站获取到使⽤B⽹站照⽚资源的⼀个通⾏令牌即可!这个令牌⽆需具备操作B⽹站所有资源的权限,也⽆需永久有效,只要满⾜A⽹站打印照⽚需求即可。
这么听来,是不是有点像单点登录?NONONO!千万不要混淆概念!单点登录是⽤户⼀次登录,⾃⼰可以操作其他关联的服务资源。OAuth2则是⽤户给⼀个系统授权,可以直接操作其他系统资源的⼀种⽅式。但SpringSecurity的OAuth2也是可以实现单点登录的!
总结⼀句:SpringSecurity的OAuth2可以做服务之间资源共享,也可以实现单点登录!⾓⾊说明
应⽤(客户端):客户端就是⼀个要访问⽤户账号的应⽤,需要得到⽤户的允许后才可以得到授权API服务(资源服务):资源服务通常提供API⽤于访问⽤户的授权客户端访问的信息
授权服务:让⽤户批准或拒绝请求的服务,严格来说,认证不属于这个服务的职责,虽然往往认证和授权都在⼀个服务。当然授权服务也可以是资源服务⽤户(资源所有者):授权客户端访问资源服务器的主体通常,作为作为OAuth2的客户端 ,需要上传这⼏个字段:Application name:应⽤名
HomepageURL:主页,主要是域名
Authorization callback URL:回调地址,授权成功后返回的URL
然后系统对于每个客户端会⽣成Client ID(必要,应⽤⼯具唯⼀标识)和Client Secret(⾮必要,可以理解为应⽤的密码),请求授权要求客户端传⼊这两个值进⾏授权
OAuth2.0中主流的四种授权⽅式为了说明四种模式先准备⼀张图授权码模式(authorization code)流程
说明:【A服务客户端】需要⽤到【B服务资源服务】中的资源
第⼀步:【A服务客户端】将⽤户⾃动导航到【B服务认证服务】,这⼀步⽤户需要提供⼀个回调地址,以备【B服务认证服务】返回授权码使⽤。
第⼆步:⽤户点击授权按钮表⽰让【A服务客户端】使⽤【B服务资源服务】,这⼀步需要⽤户登录B服务,也就是说⽤户要事先具有B服务的使⽤权限。第三步:【B服务认证服务】⽣成授权码,授权码将通过第⼀步提供的回调地址,返回给【A服务客户端】。注意这个授权码并⾮通⾏【B服务资源服务】的通⾏凭证。
第四步:这个时候,通常会给⽤户弹出⼀个页⾯,询问⽤户是否同意授权给A服务,⽤户点击同意,然后【A服务认证服务】携带上⼀步得到的授权码向【B服务认证服务】发送请求,获取通⾏凭证token。
第五步:【B服务认证服务】给【A服务认证服务】返回令牌token和更新令牌refresh token。使⽤场景
授权码模式是OAuth2中最安全最完善的⼀种模式,应⽤场景最⼴泛,可以实现服务之间的调⽤,常见的微信,QQ等第三⽅登录也可采⽤这种⽅式实现。简化模式(implicit)流程
说明:简化模式中没有【A服务认证服务】这⼀部分,全部⼜【A服务客户端】与B服务交互,整个过程不再有授权码,token直接暴露在浏览器。
第⼀步:【A服务客户端】将⽤户⾃动导航到【B服务认证服务】,这⼀步⽤户需要提供⼀个回调地址,以备【B服务认证服务】返回token使⽤,还会携带⼀个【A服务客户端】的状态标识state。
第⼆步:⽤户点击授权按钮表⽰让【A服务客户端】使⽤【B服务资源服务】,这⼀步需要⽤户登录B服务,也就是说⽤户要事先具有B服务的使⽤权限。第三步:【B服务认证服务】⽣成通⾏令牌token,token将通过第⼀步提供的回调地址,返回给【A服务客户端】。使⽤场景
适⽤于A服务没有服务器的情况。⽐如:纯⼿机⼩程序,JavaScript语⾔实现的⽹页插件等。密码模式(resource owner password credentials)流程
第⼀步:直接告诉【A服务客户端】⾃⼰的【B服务认证服务】的⽤户名和密码
第⼆步:【A服务客户端】携带【B服务认证服务】的⽤户名和密码向【B服务认证服务】发起请求获取token。第三步:【B服务认证服务】给【A服务客户端】颁发token。使⽤场景
此种模式虽然简单,但是⽤户将B服务的⽤户名和密码暴露给了A服务,需要两个服务信任度⾮常⾼才能使⽤。客户端模式(client credentials)流程
说明:这种模式其实已经不太属于OAuth2的范畴了。A服务完全脱离⽤户,以⾃⼰的⾝份去向B服务索取token。换⾔之,⽤户⽆需具备B服务的使⽤权也可以。完全是A服务与B服务内部的交互,与⽤户⽆关了。第⼀步:A服务向B服务索取token。第⼆步:B服务返回token给A服务。使⽤场景
A服务本⾝需要B服务资源,与⽤户⽆关。JWS/JWK
Oauth2中返回的token其实也有很多种类型,SpringSecurityOauth2中授权服务器如果不做配置,那么默认返回的其实只是⼀串UUID。
那么我们使⽤怎样的token呢?当然还是JWT啦!
SpringSecurityOauth2中授权服务器签发的token还是使⽤⾮对称加密进⾏签名,但是其内部已经实现了相关逻辑,不再需要我们⾃⼰去写逻辑,配置好之后直接使⽤即可。
不过这⾥还需要了解⼀个术语:JWS/JWK
JWT⽕爆之后,⼈们对于其安全性做了很多讨论,其签名也是⼈们讨论的话题之⼀。JWT⽀持使⽤不同的算法进⾏签名,但是没有⼀个统⼀的⽅式。JWS就是JWT签名的验证数据完整性的不同的加密机制
JWK就是签名加密密钥的JSON结构。⼀般情况下,对于签名需要有⼀个不对称加密,需要有密钥对进⾏加密。公钥和私钥。公钥加密需要私钥来解密,同样的私钥加密需要公钥来解密。
⼀般公钥和私钥放在不同的地⽅,私钥保存在服务器上⾯,⽽公钥保存在客户端。公钥可以公开,私钥保密。
签发token使⽤私钥加密,签名。token的内容是公开的,但是token的签名验证需要公钥去解密验证,没有私钥是伪造不出来私钥加密的签名的。只要验证成功,说明这个token是使⽤私钥签发的,是可以信任的流程:
客户端请求Access Token,资源服务器返回⼀个使⽤JWS签名的⼀个JWT,这⾥的JWS包含⼀个Kid,其为⼀种加密形式的唯⼀标识,表⽰了应该使⽤说明⽅式进⾏加密。
客户端请求资源,将使⽤JWS签名的⼀个JWT传递给资源服务器,资源服务器会向授权服务器请求⼀个公钥,授权服务器会把JWK(即Kid对应的这种密钥结构)返回给资源服务器,之后资源服务器就使⽤这个公钥去验证签名,去验证权限。加密流程
加密流程也就是创建JWT的过程
拿私钥进⾏⾮对称加密,将kid和其kid value写⼊jws的header中,然后在进⾏Claims声明进⾏编码然后将jws header放⼊签名这个字段⾥⾯去,进⾏编码最后就形成了有header,有cliams,有签名的⼀个jwt解密流程
拿到JWT之后,去请求⼀个公钥,对这个JWT进⾏⼀个解析
解析完成之后,得到签名,然后取出其中Kid为key对应的Kid value然后将Kid value设置到签名当中然后在去验证签名是否正确
因篇幅问题不能全部显示,请点此查看更多更全内容