手把手教你学会 基于JWT的单点登录 (2)

  spring boot 框架先搭起来,由于是简易项目,除 spring boot web 基本依赖,只需要如下的额外依赖:

<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.4</version> </dependency> <dependency> <groupId>com.auth0</groupId> <artifactId>java-jwt</artifactId> <version>3.7.0</version> </dependency>

完整的 POM 文件,请到 github 上查看.

后台实现

  后台做的事情并不多,只有以下 5 个方法:

/login : 登录成功后签发一个 jwt token
在 demo 中只是简单对比用户名密码如果是一样的认为登录成功,返回 token

/checkJwt : 检查 jwt 的有效性
检查传来的 jwt-token 是否有效,返回失效的 jwt 列表

/refreshjwt : 刷新 jwt
判断该 jwt 是否快要过期,如果快要过期,生成一个新的 jwt 返回

/inValid : 让某个 jwt 失效
jwt 如何失效一直是一个比较麻烦的问题,各有利弊。本例中采用的是为每个 jwt 生成一个随机的秘钥 secret,将 jwt--secret 保存到 redis 中,想要让某个 jwt 失效,只需将该记录在 redis 中删除即可(这样在解密时便无法获取到 secret)。但是这样让无状态的认证机制变成有状态了(记录了 jwt 和 secret 的对应关系)。

  总结来说 SSO 后台主要只做了两件事:验证用户名密码返回 jwt;验证 jwt 是否合法。具体代码查看 github 上 sso 目录下的代码。

前台实现

  前台的逻辑较为复杂,不是那么容易理解,不明白的多看几遍上面的流程图。

  再次回到 SSO 的重点:分享登录状态。要如何在前台将登录状态(在这里就是 jwt 字符串)分享出去呢?由于浏览器的限制,除了 cookie 外没有直接共享数据的办法。既然没有直接共享,那肯定是有间接的办法的!

  这个办法就是回调。系统 A 的前台在跳转到 SSO 的前台时,将当前路径作为 url 参数传递给 sso 前台,sso 前台在获取到 jwt 后,再跳转到系统 A 传过来的 url 路径上,并带上 jwt 作为 url 参数。这就完成了 jwt 的一次共享,从 sso 共享到系统 A。

打个比方:你点了个外卖,别人要怎么把外卖给你呢?显然你会留下的地址,让别人带上饭送到这个地址,然后你就能享用美食了。这和 jwt 的传递非常相识了。

系统 A 说:我要 jwt,快把它送到:8081/test1/这个地址上。

SSO 说:好嘞,这个地址是合法的可以送 jwt 过去,这就跳转过去::8081/test1/?jwt=abcdefj.asdf.asdfasf

系统 A 说:不错不错,真香。

  要注意这里有个坑就是:如果另外一个恶意系统 C 安装相同的格式跳转到 SSO,想要获取 jwt,这显然是不应该给它的。所以在回跳回去的时候要判断一下这个回调地址是不是合法的,能不能给 jwt 给它,可以向后台请求判断也可以在 sso 前台直接写死合法的地址。在 demo 是没有这个判断过程的。

实现业务系统

  业务系统代码非常简单,主要是用了一个拦截器,拦截 http 请求,提取出 token 向 sso 认证中心验证 token 是否有效,有效放行,否则返回错误给前端。太简单也不贴代码了,到 github 上看看就明白了。

效果

  上面说了一大串都是原理了,其实这个难也就难在原理部分,代码实现并没有那么复杂。这里就不贴代码了,有需要直接到 github 上看。

  这里上几个效果图:

系统 A 首次登陆系统

系统A登陆gif

可以看到首次登陆是需要跳到 sso 认证中心输入用户名密码进行登陆验证的。登陆成功回跳后接口请求成功。

将 A 的启动端口改为 8082 后再次启动,当作系统 B

系统B登陆gif

可以看到这次是无需登陆的,跳到认证中心后就马上跳回了,如果去掉 alert 一般是看不出跳转过程的。

最后在任意一个系统注销,都会让所有的系统推出登陆。

可以看到,在系统 A 登录系统后,系统 B,系统 C 都不再需要输入用户名密码进行登录。如果速度足够快甚至都注意不到调到 SSO 再跳回来的过程。

源码:github

本篇原创发布于:

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zyfpww.html