分布式环境下的单点登录(SSO)是一种允许用户在多个相互独立的应用系统中,通过一次登录即可访问所有相关系统的技术,这种机制极大地简化了用户的登录过程,提高了用户体验,并减少了因多次登录带来的安全风险。
一、基于Session的身份认证
1. 简介
对于一个Web应用,客户端每次请求时,服务器都会打开一个新的会话,而且服务器不会维护客户端的上下文信息,因此如何管理客户端会话是必须要解决的问题,HTTP是无状态的协议,所以它提供了一种机制,通过Session来保存上下文信息,为每个用户分配一个sessionId,并且每个用户收到的sessionId都不一样,变量的值保存在服务器端。
2. 实现
可以通过定义一个Filter进行拦截非登录请求,然后确认当前请求的Session中是否能够拿到用户信息,如果能拿到用户信息,那么就是登录状态,否则,认定当前请求无效,将请求转发到登录页面即可。
public class LoginFilter implements Filter { @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) servletRequest; HttpServletResponse response = (HttpServletResponse)servletResponse; Object user = request.getSession().getAttribute(CommonConstants.USER_ATTR);; String requestUrl = request.getServletPath(); //非登陆页面并且不是登陆状态 if (!requestUrl.startsWith("/login")&& null == user) { //则拒绝当前请求,请求转发到登陆页面 request.getRequestDispatcher("/login").forward(request,response); return ; } filterChain.doFilter(request,servletResponse); } @Override public void destroy() { } @Override public void init(FilterConfig filterConfig) throws ServletException { } }
二、分布式Session共享
1. 简介
随着分布式架构的演进,单个服务器已经不能满足系统的需要了,通常都会把系统部署在多台服务器上,通过Nginx负载均衡把请求分发到其中的一台服务器上,这样很可能同一个用户的请求被分发到不同的服务器上,因为Session是保存在服务器上的,那么很有可能第一次请求访问的服务器A,创建了Session,但是第二次访问到了服务器B,这时就会出现取不到Session的情况,因此要在集群环境下使用,最好的解决办法就是使用Session共享。
2. 实现
整个实现的核心点就是通过定义一个Request请求对象的Wrapper包装类,负责对当前Request请求的Session获取逻辑进行重写,将Session信息交由Redis进行存储和管理,包括从Redis获取Session信息以及认证成功后将Session信息提交到Redis中。
public class RedisRequestWrapper extends HttpServletRequestWrapper { private volatile boolean committed = false; private String uuid = UUID.randomUUID().toString(); // ... 具体实现略 ... }
三、单点登录(SSO)
1. 简介
单点登录系统主要解决统一认证授权的问题,在多个应用系统中,只需要登录一次,就可以访问其他相互信任的应用系统,想要完成单点登录的效果,必须先统一管理用户信息,其他应用系统必须配合完成改造和对接。
2. 实现流程
当用户输入用户名和密码之后点击提交按钮,将数据传给JT-WEB服务器,JT-WEB利用RPC方式访问JT-SSO校验数据是否有效,如果校验的数据准备无误后将用户信息保存到Redis中,key使用uuid,value使用userJSON,并且设定7天超时,JT-SSO将服务器数据返回给JT-WEB服务器,JT-WEB服务器将数据保存到Cookie中,要求实现Cookie共享。
四、跨域分布式系统单点登录的实现(CAS单点登录)
1. 场景说明
子系统A域名:www.a.com;子系统B域名:www.b.com;CAS系统域名:www.cas.com。
2. 概念说明
全局票据:一个全局唯一的uuid,存放在域名为 .cas.com 的 Cookie 中,是用户已登录的标识。
临时票据:一个全局唯一的uuid,存放在Redis中,有过期时限,用于验证用户的身份。
3. 实现逻辑
用户访问子系统A的页面,子系统A的页面检查参数中是否包含临时票据,此时是没有的,则什么都不做,子系统A的页面请求子系统A的后台接口,子系统A后台检查当前系统的Cookie中是否存在用户ID,因为从未登录过,所以Cookie中是不存在用户ID的,因此子系统A后台返回未登录给客户端,客户端将当前子系统A页面的 url 作为参数,重定向到CAS系统的登录页面,用户在CAS系统的登录页面填写用户名、密码后提交登录,CAS系统后台校验用户名、密码通过后生成一个全局唯一的 uuid作为全局票据,将全局票据存储在域名为 .cas.com 的 Cookie 中,以全局票据为 key,用户ID为 value存到 Redis 中,再生成一个 uuid作为临时票据以临时票据为 key临时票据为 value存储到Redis中5分钟过期,CAS系统返回临时票据给客户端,客户端将页面重定向回子系统A的页面临时票据作为参数携带,子系统A的页面检查参数中是否有临时票据此时是有的则子系统A的页面Ajax调用CAS后台的用户身份验证接口以临时票据作为参数,CAS用户身份验证接口以临时票据为key从redis中获取value值不为空则验证成功然后清空Redis中的临时票据,从CAS系统的Cookie中得到全局票据以全局票据为key从Redis中得到用户ID返给子系统A的页面,子系统A的页面拿到用户ID后存储在域名为 .a.com 的 Cookie 中然后继续完成业务接口逻辑,子系统A再次访问业务接口时后台检查当前系统的Cookie中是否存在用户ID此时是存在的,后台使用用户ID到Redis中获取完整的用户信息然后完成接口逻辑,如果Redis中用户信息不存在则表示用户已注销登录则返回未登录,用户访问子系统B的过程与访问子系统A类似,用户注销时首先清空当前子系统中用户ID的Cookie然后子系统前端页面Ajax访问CAS系统的用户注销接口,CAS系统从Cookie中拿到全局票据根据全局票据从Redis中得到用户ID删除Cookie中的全局票据从Redis中删除 key为 全局票据的数据从Redis中删除 key为用户ID的数据。
五、相关问题与解答栏目
问题1:在分布式环境下实现单点登录时需要注意哪些安全问题?
答案:在分布式环境下实现单点登录时需要注意以下安全问题:确保传输过程中的安全性,使用HTTPS加密通信;保护好用户的凭据信息,避免明文传输;对敏感数据进行加密存储;定期审计和更新安全策略;防止CSRF攻击等。
问题2:如何在跨域情况下实现单点登录?
答案:在跨域情况下实现单点登录可以采用CAS(中央认证服务)的方式,通过CAS系统作为中心认证服务器来实现跨域的单点登录功能,具体实现可以参考上述文章中提到的CAS单点登录流程。
小伙伴们,上文介绍了“分布式环境下单点登录”的内容,你了解清楚吗?希望对你有所帮助,任何问题可以给我留言,让我们下期再见吧。
原创文章,作者:K-seo,如若转载,请注明出处:https://www.kdun.cn/ask/668218.html