背景:
当下架构网站,大多是微服务架构。分布式架构。很多功能都是单独的项目。那么验证是否登录就会变得麻烦。
分类:
cookie的顶级域名共享。
设置sso项目单点登录。
sso单点登录
-
- 当浏览器访问系统1,首先判断是否有登录信息。
- 没有访问sso系统判断是否登录,没有登陆。
- 跳转登录页面拿到用户名密码。
- 在sso登录留下登录信息。返回系统1登陆令牌.
- 系统1拿着令牌访问sso检验令牌是否正确。
- 访问正确,sso注册系统1。系统1留下登录信息。
-
- 统一用户访问系统2 ,发现没有登陆。
- 带着自己的地址参数,访问sso,发现已经登陆。
- 拿到登陆令牌,返回给系统2.
- 系统2拿着令牌到sso检验令牌。
- 令牌没问题,sso留下系统2信息。系统2留下登录信息。
注销
- 用户向系统1发起注销请求
- 系统1根据用户与系统1建立的会话id拿到令牌,向sso认证中心发起注销请求
- sso认证中心校验令牌有效,销毁全局会话,同时取出所有用此令牌注册的系统地址
- sso认证中心向所有注册系统发起注销请求
- 各注册系统接收sso认证中心的注销请求,销毁局部会话
- sso认证中心引导用户至登录页面
实现
-
sso-client拦截未登录请求
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse res = (HttpServletResponse) response;
HttpSession session = req.getSession();
if (session.getAttribute("isLogin")) {
chain.doFilter(request, response);
return;
}
//跳转至sso认证中心
res.sendRedirect("sso-server-url-with-system-url");
}
-
- 上述代码使用了,servlet的过滤器Filter。他主要实现了拦截一个http请求。在当前项目的会话作用域中是否有登陆信息。如果有登录信息那么就放行。没有登陆信息,就跳转诉讼认证中心。
- 过滤器其实可以使用 框架中的拦截器拦截,而且检查时不一定用会话作用域。
- redis可以作为登录的消息存放。
- 使用拦截器拦截请求。判断当先项目连接的redis中是否存在登陆消息。有登陆消息就放行。没有则使用rpc远程调用sso的登陆检查。当sso发现自己没有登陆,跳转登陆页面。然后将登陆消息存放在sso项目连接的redis。
- 将登陆消息和是哪一个系统通过 list集合绑定,以token为key,list中当那些系统登录了。方便注销的时候sso发送注销消息。
-
sso-server拦截未登录请求
sso的验证和上面的原理一样。当sso中也没有登陆时,就会跳转登陆页面 。
-
sso-server验证用户登录信息
@RequestMapping("/login")
public String login(String username, String password, HttpServletRequest req) {
this.checkLoginInfo(username, password);
req.getSession().setAttribute("isLogin", true);
return "success";
}
-
- 上述代码使用的是会话作用域将登陆消息保存。
- 其实,在分布式中当sso查询到人物消息允许登录时 ,使用jwt将个人消息包装成一个token字符串,这个就是登陆令牌。保存至sso连接的redis作为登陆缓存。并且作为返回jwt到原系统,原系统存放到redis作为登录缓存。
-
sso-client取得令牌并校验
// 请求附带token参数
String token = req.getParameter("token");
if (token != null) {
// 去sso认证中心校验token
boolean verifyResult = this.verify("sso-server-verify-url", token);
if (!verifyResult) {
res.sendRedirect("sso-server-url");
return;
}
chain.doFilter(request, response);
}
-
- 上述代码将token传回到sso验证token是否合法。
- 其实可以rpc远程调用到sso的redis查看是否有这个token。而且可以使用一个布隆过滤器。然后检查jwt字符串的合法性。都ok就可以传回true;
-
注销过程
sso通过jwt确认一个人的token。通过token找到登陆消息。redis中保存了那些系统登录了,有一个list集合。sso向这些系统发送注销这个jwt的消息。然后sso本体删除这个登陆消息。