单点登录(Single Sign On),简称为 SSO,是比较流行的企业业务整合的解决方案之一。SSO的定义是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统。
对于相同父域名下的单点登录比较简单,只需要将cookie的作用域放大到父域名即可。
1 | java复制代码@Bean |
本文主要分享一下不同应用服务器之间(即不同域名)的单点登录流程。
- 单点登录流程
单点登录流程图如下
- 假设现在第一次访问Client1的受保护的资源,由于我们没有登录,则需要跳转到登录服务器进行登录,但是登录之后应该跳到哪里呢?很显然,需要跳回到我们想要访问的页面,所以在重定向到登录服务器时带上回调地址redirectURL。
1 | java复制代码@GetMapping("/abc") |
- 浏览器展示登录页
- 用户输入账号密码进行登录,并在隐藏域提交回调地址
- 登录服务器查询数据库,验证账号及密码。账号密码正确,则生成一个令牌sso_token,保存到cookie中(该cookie只存在于登录服务器),并将登录用户信息以sso_token为key,保存到redis中(剧透,顺便保存回调地址到redis)。然后携带上令牌重定向到回调地址(即登录前页面)。
1 | java复制代码@PostMapping("/login") |
- 应用服务器1拿到token,需要向验证服务器发起请求(也可以直接到redis中查是否存在这个key),验证是否存在该token。目的是为了防止伪造令牌。验证通过,则保存用户信息到本地session,(下次访问则无需经过登录服务器,判断session中存在用户即可),返回用户想到访问的含受保护资源页面。
1 | java复制代码@ResponseBody |
1 | java复制代码@GetMapping("/abc") |
- 用户再次发起请求,访问Client2中受保护的资源,同样会先到登录服务器的登录页面,但此时会带上cookie,登录服务器一看,有cookie,就知道这是一个在其他系统登录过的用户,就发放一个令牌,重定向到用户访问的地址。
1 | java复制代码@GetMapping("/login.html") |
- 应用服务器2拿到令牌,同样需要到登录服务器进行验证,验证成功则保存用户信息到本地session,返回访问资源页面。
- 应用服务器判断用户是否登录,第一次看是否携带令牌,之后就看本地session中有没有登录用户的信息。
- 登录服务器判断用户是否登录,第一次就到数据库查询,之后就看是否携带cookie。
- 单点登出流程
话不多说,先放个单点登出的流程图。
- 用户点击注销按钮,携带令牌到登录服务器进行验证,同样需要携带上回调地址(一般为公共资源页面即可),作为登出后展示在浏览器的页面。
你是不是有几个疑问呢。为什么退出登录也需要携带令牌?本地session中只保存了登录用户的基本信息,那要如何携带令牌到登录服务器呢?不着急,下面就为你解答。
* 携带令牌的目的是为了验证改退出请求是登录用户发起的,防止其他人恶意请求。
* 对于获取token,我们可以利用SessionID来获取token,所以我们必须在登录成功后,保存用户信息到session的同时,也保存SessionID和token的映射关系(可以使用静态map来保存)。
1 | java复制代码// SessionID->token |
1 | java复制代码@GetMapping("/logout") |
- 登录服务器验证成功,向已经登陆的所有应用服务器发起注销请求(带上令牌)。所以我们需要知道有哪些应用服务器登陆了。这就是我在上面剧透的,登录服务器在验证登录时保存应用服务器地址。
1 | java复制代码private void addLoginUrl(String url){ |
1 | java复制代码@GetMapping("/logOut") |
- 应用服务器收到登录服务器的注销请求,首先验证令牌,判断是否是登录服务器发起的注销请求。
1 | java复制代码@ResponseBody |
* 这里尤其需要注意,需要获取指定session。登录服务器发送过来的请求,如果直接request.getSession().getId()获取,这样获取到的是新的session,并不是保存用户信息的会话。
* 为解决这一问题,在保存用户信息到本地session的同时,使用静态map来保存session,以令牌作为key。
1
2
java复制代码// token->session
private static final Map<String, HttpSession> localSession = new HashMap<>();
至此,单点登录功能基本实现。如果感兴趣,欢迎到我的github仓库获取源码。如果觉得有用的话,欢迎start。
本文转载自: 掘金