🏮🏮🏮
使用token实现单点登录
SpringSecurity
什么是安全框架?
解决系统安全问题的框架。如果没有安全框架,我们需要手动处理每个资源的访问控制,非常麻烦。使用安全框架,我们可以通过配置的方式实现对资源的访问限制。
常用安全框架
Spring Security:Spring家族一员。是一个能够为基于Spring的企业应用系统提供声明式的安全访 问控制解决方案的安全框架。它提供了一组可以在Spring应用上下文中配置的Bean,充分利用了 Spring IoC , DI(控制反转Inversion of Control,DI:Dependency Injection 依赖注入) 和 AOP(面向切面编程) 功能,为应用系统提供声明式的安全访问控制功能,减少了为企业系统安 全控制编写大量重复代码的工作。
Apache Shiro:一个功能强大且易于使用的Java安全框架,提供了认证,授权,加密,和会话管理。
Spring Security简介
概述 Spring Security是一个高度自定义的安全框架。利用 Spring IoC/DI和AOP功能,为系统提供了声明 式安全访问控制功能,减少了为系统安全而编写大量重复代码的工作。使用 Spring Secruity 的原因有 很多,但大部分都是发现了 javaEE的 Servlet 规范或 EJB 规范中的安全功能缺乏典型企业应用场景。同 时认识到他们在 WAR 或 EAR 级别无法移植。因此如果你更换服务器环境,还有大量工作去重新配置你 的应用程序。使用 Spring Security解决了这些问题,也为你提供许多其他有用的、可定制的安全功能。 正如你可能知道的两个应用程序的两个主要区域是“认证”和“授权”(或者访问控制)。这两点也是 Spring Security 重要核心功能。“认证”,是建立一个他声明的主体的过程(一个“主体”一般是指用户, 设备或一些可以在你的应用程序中执行动作的其他系统),通俗点说就是系统认为用户是否能登录。 “授权”指确定一个主体是否允许在你的应用程序执行一个动作的过程。通俗点讲就是系统判断用户是否 有权限去做某些事情。
SpringSecurity项目搭建
1、配置pom文件,引入jar包
1 | <!--spring security 组件--> |
2、登陆界面
1 |
|
访问页面 导入spring-boot-starter-security 启动器后,Spring Security 已经生效,默认拦截全部请求,如果用户没有登录,跳转到内置登录页面。
UserDetailsService
当什么也没有配置的时候,账号和密码是由 Spring Security 定义生成的。而在实际项目中账号和密 码都是从数据库中查询出来的。所以我们要通过自定义逻辑控制认证逻辑。如果需要自定义逻辑时,只需要实现 UserDetailsService 接口即可。

1、创建user实体类实现UserDetails
1 | public class User implements UserDetails { |
Oauth2
简介
第三方认证技术方案最主要是解决认证协议的通用标准问题,因为要实现跨系统认证,各系统之间要 遵循一定的接口协议。
OAUTH协议为用户资源的授权提供了一个安全的、开放而又简易的标准。同时,任何第三方都可以 使用OAUTH认证服务,任何服务提供商都可以实现自身的OAUTH认证服务,因而OAUTH是开放的。业 界提供了OAUTH的多种实现如PHP、JavaScript,Java,Ruby等各种语言开发包,大大节约了程序员的 时间,因而OAUTH是简易的。互联网很多服务如Open API,很多大公司如Google,Yahoo, Microsoft等都提供了OAUTH认证服务,这些都足以说明OAUTH标准逐渐成为开放资源授权的标准。
Oauth协议目前发展到2.0版本,1.0版本过于复杂,2.0版本已得到广泛应用。
参考:https://baike.baidu.com/item/oAuth/7153134?fr=aladdin
Oauth 协议:https://tools.ietf.org/html/rfc6749
Oauth2认证的例子

1、用户进入网站的登录页面,点击微信的图标以微信账号登录系统,用户是自己在微信里信息的资源 拥有者。
2、 资源拥有者同意给客户端授权 资源拥有者扫描二维码表示资源拥有者同意给客户端授权,微信会对资源拥有者的身份进行验证,验 证通过后,微信会询问用户是否给授权网站访问自己的微信数据,用户点击“确认登录”表示同意授权, 微信认证服务器会颁发一个授权码,并重定向到网站。
3、客户端获取到授权码,请求认证服务器申请令牌 此过程用户看不到,客户端应用程序请求认证服务器,请求携带授权码。
4、认证服务器向客户端响应令牌 认证服务器验证了客户端请求的授权码,如果合法则给客户端颁发令牌,令牌是客户端访问资源的通 行证。此交互过程用户看不到,当客户端拿到令牌后,用户在网站看到已经登录成功。
5、客户端请求资源服务器的资源 客户端携带令牌访问资源服务器的资源。网站携带令牌请求访问微信服务器获取用户的基本信息。
6、资源服务器返回受保护资源 资源服务器校验令牌的合法性,如果合法则向用户响应资源信息内容。
注意:资源服务器和认证服务器可以是一个服务也可以分开的服务,如果是分开的服务资源服务器通常 要请求认证服务器来校验令牌的合法性。
Oauth2.0认证流程如下:
引自Oauth2.0协议rfc6749 https://tools.ietf.org/html/rfc6749
角色
客户端
本身不存储资源,需要通过资源拥有者的授权去请求资源服务器的资源,比如:Android客户端、Web 客户端(浏览器端)、微信客户端等。
资源拥有者
通常为用户,也可以是应用程序,即该资源的拥有者。
授权服务器(也称认证服务器)
用来对资源拥有的身份进行认证、对访问资源进行授权。客户端要想访问资源需要通过认证服务器由资 源拥有者授权后方可访问。
资源服务器
存储资源的服务器,比如,网站用户管理服务器存储了网站用户信息,网站相册服务器存储了用户的相 册信息,微信的资源服务存储了微信的用户信息等。客户端最终访问资源服务器获取资源信息。
常用术语
客户凭证(client Credentials) :客户端的clientId和密码用于认证客户;
令牌(tokens) :授权服务器在接收到客户请求后,颁发的访问令牌;
作用域(scopes) :客户请求访问令牌时,由资源拥有者额外指定的细分权限(permission);
令牌类型
授权码 :仅用于授权码授权类型,用于交换获取访问令牌和刷新令牌;
访问令牌 :用于代表一个用户或服务直接去访问受保护的资源;
刷新令牌 :用于去授权服务器获取一个刷新访问令牌;
BearerToken :不管谁拿到Token都可以访问资源,类似现金;
Proof of Possession(PoP) Token :可以校验client是否对Token有明确的拥有权;
特点
1、更安全,客户端不接触用户密码,服务器端更易集中保护;
2、广泛传播并被持续采用;
3、短寿命和封装的token;
4、资源服务器和授权服务器解耦;
5、集中式授权,简化客户端;
6、HTTP/JSON友好,易于请求和传递token;
7、考虑多种客户端架构场景 客户可以具有不同的信任级别;
缺点
协议框架太宽泛,造成各种实现的兼容性和互操作性差,不是一个认证协议,本身并不能告诉你任何用户信息。
Oauth2授权模式
授权码模式(Authorization Code)
- 第一步:用户访问页面
- 第二步:访问的页面将请求重定向到认证服务器
- 第三步:认证服务器向用户展示授权页面,等待用户授权
- 第四步:用户授权,认证服务器生成一个code和带上client_id发送给应用服务器; 然后,应用服务器拿到code,并用client_id去后台查询对应的client_secret
- 第五步:将code、client_id、client_secret传给认证服务器换取access_token和 refresh_token
- 第六步:将access_token和refresh_token传给应用服务器
- 第七步:验证token,访问真正的资源页面
优点:安全性、token可以刷新,避免多次登录、安全信息存在应用服务器暴露风险小,安全性高
缺点:多次请求
应用场景:目前市面上主流的第三方认证都是这个模式

简化授权模式(Implicit)
- 第一步:用户访问页面时,重定向到认证服务器。
- 第二步:认证服务器给用户一个认证页面,等待用户授权。
- 第三步:用户授权,认证服务器想应用页面返回Token
- 第四步:验证Token,访问真正的资源页面
优点:简单
缺点:应用没有后台、不能存储refresh_token的必要信息、Token暴露风险
应用场景:应用只有页面没有后台管理,只能使用第三方认证后直接访问,例如:调查问卷,评论

密码模式(Resource Owner PasswordCredentials)
- 第一步:用户访问用页面时,输入第三方认证所需要的信息(QQ/微信账号密码)
- 第二步:应用页面那种这个信息去认证服务器授权
- 第三步:认证服务器授权通过,拿到token,访问真正的资源页面
优点:不需要多次请求转发,额外开销,同时可以获取更多的用户信息。(都拿到账号密码了)
缺点:局限性,认证服务器和应用方必须有超高的信赖。(比如亲兄弟?)
应用场景:自家公司搭建的认证服务器

客户端模式(Client Credentials)
- 第一步:用户访问应用客户端
- 第二步:通过客户端定义的验证方法,拿到token,无需授权
- 第三步:访问资源服务器A
- 第四步:拿到一次token就可以畅通无阻的访问其他的资源页面。
这是一种最简单的模式,只要client请求,我们就将AccessToken发送给它。这种模式是最方便但最不安全的模式。因此这就要求我们对client完全的信任,而client本身也是安全的。
因此这种模式一般用来提供给我们完全信任的服务器端服务。在这个过程中不需要用户的参与。

Spring Security Oauth2架构

流程
1、用户访问,此时没有Token。Oauth2RestTemplate会报错,这个报错信息会被 Oauth2ClientContextFilter捕获并重定向到认证服务器
2、认证服务器通过Authorization Endpoint进行授权,并通过AuthorizationServerTokenServices生 成授权码并返回给客户端
3、客户端拿到授权码去认证服务器通过Token Endpoint调用AuthorizationServerTokenServices生 成Token并返回给客户端
4、客户端拿到Token去资源服务器访问资源,一般会通过Oauth2AuthenticationManager调用 ResourceServerTokenServices进行校验。校验通过可以获取资源。
Spring Security Oauth2授权码模式
1、添加依赖
1 |
|
2、实体类
1 | public class User implements UserDetails { |
3、编写service
1 |
|
4、编写控制层
1 |
|
5、编写配置类
1 |
|
授权服务器
1 |
|
资源服务器
1 |
|
6、根据授权码获取令牌(POST请求)


7、根据token去资源服务器拿资源

Spring Security Oauth2 密码模式
1、修改配置类
SecurityConfig
1 |
|
授权服务器
1 |
|
2、测试


JWT
常见的认证机制
HTTP Basic Auth
HTTP Basic Auth简单点说明就是每次请求API时都提供用户的username和password,简言之, Basic Auth是配合RESTful API 使用的最简单的认证方式,只需提供用户名密码即可,但由于有把用户 名密码暴露给第三方客户端的风险,在生产环境下被使用的越来越少。因此,在开发对外开放的 RESTful API时,尽量避免采用HTTP Basic Auth。
Cookie Auth
Cookie认证机制就是为一次请求认证在服务端创建一个Session对象,同时在客户端的浏览器端创建 了一个Cookie对象;通过客户端带上来Cookie对象来与服务器端的session对象匹配来实现状态管理 的。默认的,当我们关闭浏览器的时候,cookie会被删除。但可以通过修改cookie 的expire time使 cookie在一定时间内有效。

OAuth
OAuth(开放授权,Open Authorization)是一个开放的授权标准,允许用户让第三方应用访问该用 户在某一web服务上存储的私密的资源(如照片,视频,联系人列表),而无需将用户名和密码提供给 第三方应用。如网站通过微信、微博登录等,主要用于第三方登录。
OAuth允许用户提供一个令牌,而不是用户名和密码来访问他们存放在特定服务提供者的数据。每一 个令牌授权一个特定的第三方系统(例如,视频编辑网站)在特定的时段(例如,接下来的2小时内)内 访问特定的资源(例如仅仅是某一相册中的视频)。这样,OAuth让用户可以授权第三方网站访问他们 存储在另外服务提供者的某些特定信息,而非所有内容。

这种基于OAuth的认证机制适用于个人消费者类的互联网产品,如社交类APP等应用,但是不太适合 拥有自有认证权限管理的企业应用。
缺点:过重。
Token Auth
使用基于 Token 的身份验证方法,在服务端不需要存储用户的登录记录。大概的流程是这样的:
1、客户端使用用户名跟密码请求登录
2、服务端收到请求,去验证用户名与密码
3、验证成功后,服务端会签发一个 Token,再把这个 Token 发送给客户端
4、客户端收到 Token 以后可以把它存储起来,比如放在 Cookie 里
5、客户端每次向服务端请求资源的时候需要带着服务端签发的 Token
6、服务端收到请求,然后去验证客户端请求里面带着的 Token,如果验证成功,就向客户端返回请 求的数据
Token Auth的优点(Token机制相对于Cookie机制又有什么好处呢?):
1、支持跨域访问: Cookie是不允许垮域访问的,这一点对Token机制是不存在的,前提是传输的用户 认证信息通过HTTP头传输.
2、无状态(也称:服务端可扩展行):Token机制在服务端不需要存储session信息,因为Token 自身包 含了所有登录用户的信息,只需要在客户端的cookie或本地介质存储状态信息.
3、更适用CDN: 可以通过内容分发网络请求你服务端的所有资料(如:javascript,HTML,图片 等),而你的服务端只要提供API即可.
4、去耦: 不需要绑定到一个特定的身份验证方案。Token可以在任何地方生成,只要在你的API被调用 的时候,你可以进行Token生成调用即可.
5、更适用于移动应用: 当你的客户端是一个原生平台(iOS, Android,Windows 10等)时,Cookie 是不被支持的(你需要通过Cookie容器进行处理),这时采用Token认证机制就会简单得多。
6、CSRF:因为不再依赖于Cookie,所以你就不需要考虑对CSRF(跨站请求伪造)的防范。
7、性能: 一次网络往返时间(通过数据库查询session信息)总比做一次HMACSHA256计算的Token 验证和解析要费时得多.
8、不需要为登录页面做特殊处理: 如果你使用Protractor 做功能测试的时候,不再需要为登录页面做 特殊处理.
9、基于标准化:你的API可以采用标准化的 JSON Web Token (JWT). 这个标准已经存在多个后端库 (.NET, Ruby, Java,Python, PHP)和多家公司的支持(如:Firebase,Google, Microsoft).
JWT简介
JSON Web Token(JWT)是一个开放的行业标准(RFC 7519),它定义了一种简介的、自包含的协 议格式,用于在通信双方传递json对象,传递的信息经过数字签名可以被验证和信任。JWT可以使用 HMAC算法或使用RSA的公钥/私钥对来签名,防止被篡改。
官网: https://jwt.io/ 标准: https://tools.ietf.org/html/rfc7519
JWT令牌的优点:
1、jwt基于json,非常方便解析。
2、可以在令牌中自定义丰富的内容,易扩展。
3、通过非对称加密算法及数字签名技术,JWT防止篡改,安全性高。
4、资源服务使用JWT可不依赖认证服务即可完成授权。
缺点:
1、 JWT令牌较长,占存储空间比较大。
JWT组成:
一个JWT实际上就是一个字符串,它由三部分组成,头部、载荷与签名。
头部(Header)
头部用于描述关于该JWT的最基本的信息,例如其类型(即JWT)以及签名所用的算法(如HMAC SHA256或RSA)等。这也可以被表示成一个JSON对象。
1 | typ: 是类型。 |
Base64 是一种基于64个可打印字符来表示二进制数据的表示方法。由于2的6次方等于64,所以每6 个比特为一个单元,对应某个可打印字符。三个字节有24个比特,对应于4个Base64单元,即3个字节 需要用4个可打印字符来表示。JDK 中提供了非常方便的 BASE64Encoder 和 BASE64Decoder ,用它们 可以非常方便的完成基于 BASE64 的编码和解码。
负载(Payload)
第二部分是负载,就是存放有效信息的地方。这个名字像是特指飞机上承载的货品,这些有效信息包含 三个部分:
标准中注册的声明(建议但不强制使用)
1 | iss: jwt签发者 |
公共的声明
公共的声明可以添加任何的信息,一般添加用户的相关信息或其他业务需要的必要信息.但不建议添加 敏感信息,因为该部分在客户端可解密.
私有的声明
私有声明是提供者和消费者所共同定义的声明,一般不建议存放敏感信息,因为base64是对称解密 的,意味着该部分信息可以归类为明文信息。
签证、签名(signature)
jwt的第三部分是一个签证信息,这个签证信息由三部分组成:
1、header (base64后的)
2、payload (base64后的)
3、secret(盐,一定要保密)
这个部分需要base64加密后的header和base64加密后的payload使用.连接组成的字符串,然后通过 header中声明的加密方式进行加盐secret组合加密。
注意: secret 是保存在服务器端的, jwt 的签发生成也是在服务器端的, secret 就是用来进行 jwt 的签发和 jwt 的验证,所以,它就是你服务端的私钥,在任何场景都不应该流露出去。一旦客户端得知 这个 secret , 那就意味着客户端是可以自我签发 jwt 了。
JJWT简介
JJWT是一个提供端到端的JWT创建和验证的Java库。永远免费和开源(Apache License,版本2.0),JJW 很容易使用和理解。它被设计成一个以建筑为中心的流畅界面,隐藏了它的大部分复杂性。
规范官网:https://jwt.io/
创建项目
1、添加依赖
1 |
|
2、测试Token
1 |
|
Spring Security Oauth2 整合JWT
1、添加配置文件
1 |
|
2、授权服务器
1 |
|
发现获取到的令牌已经变成了JWT令牌,将access_token拿到https://jwt.io/ 网站上去解析
扩展JWT中存储的内容
有时候我们需要扩展JWT中存储的内容,这里我们在JWT中扩展一个 key为enhance,value为 enhance info 的数据。
1、添加扩展配置文件
1 |
|
2、创建一个JwtTokenEnhancer实例
1 |
|
3、授权服务器配置中配置JWT的内容增强器
1 |
|
Java中解析JWT中的内容
1、添加依赖
1 | <!--jwt 依赖--> |
2、修改控制文件
1 |
|
将令牌放入Authorization头中,访问如下地址获取信息: http://localhost:8080/user/getCurrentUser

刷新令牌
在Spring Cloud Security 中使用oauth2时,如果令牌失效了,可以使用刷新令牌通过refresh_token 的授权模式再次获取access_token。
只需修改认证服务器的配置,添加refresh_token的授权模式即可。
1 | // 授权服务器 |

Spring Security Oauth2 整合单点登录(SSO)
创建客户端
1、添加依赖
1 |
|
2、修改配置文件
1 | # 应用服务 WEB 访问端口 |
3、启动类上添加单点登录
1 |
|
4、添加控制层获取用户登录信息
1 |
|
5、修改认证服务器配置
将绑定的跳转路径修改为 http://localhost:8081/login,并添加获取秘钥时的身份认证;
1 |
|
- 本文作者:
腾飞
- 本文链接:
https://www.tengfei.eu.org/article/5253b791.html
- 版权声明: 本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。转载请注明出处!