SSO单点登录核心原理

本文涉及的产品
云数据库 Redis 版,社区版 2GB
推荐场景:
搭建游戏排行榜
简介: SSO单点登录核心原理

登录接口

@RequestMapping("/doLogin")
  @ResponseBody
  public SysResult login(User user,HttpServletResponse response) {
    //1.校验数据是否正确.获取密钥
    String ticket = userService.findUserByUP(user);
    if(StringUtils.isEmpty(ticket)) {
      return SysResult.fail();
    }
    //2.如果程序执行到这里.表示密钥有值.写入cookie
    Cookie cookie = new Cookie("JT_TICKET", ticket);
    cookie.setMaxAge(7 * 24 * 3600);
    cookie.setPath("/");
    //设定cookie的共享! 这样当访问order.jt.com或者cart.jt.com的时候都会带上这个Cookie
    cookie.setDomain("jt.com");
    //将cookie写入客户端
    response.addCookie(cookie);
    return SysResult.success();
  }

其中userService.findUserByUP(user);方法是:

@Override
  public String findUserByUP(User user) {
    String ticket = null;
    //为了与数据库数据一致,需要将密码加密
    String md5Pass = DigestUtils.md5DigestAsHex(user.getPassword().getBytes());
    user.setPassword(md5Pass);
    QueryWrapper<User> queryWrapper = new QueryWrapper<User>(user);
    //根据用户名和密码校验数据
    User userDB = userMapper.selectOne(queryWrapper);
    if(userDB !=null) {
      //将数据库数据转化为json保存到redis中
      String uuid = UUID.randomUUID().toString();
      ticket = DigestUtils.md5DigestAsHex(uuid.getBytes());
      //进行脱敏处理   100xxx0311  
      userDB.setPassword("123456你信吗??");
      String userJSON = 
          ObjectMapperUtil.toJSON(userDB);
      jedisCluster.setex(ticket,7*24*3600, userJSON);
    }
    return ticket;
  }

拦截器

当访问xxx.jt.com的时候会带上登录返回的Cookie 拦截器中配置了校验Cookie的方法,具体实现如下:

@Component //交给spring容器管理
public class UserInterceptor implements HandlerInterceptor{
  private static final String TICKET = "JT_TICKET";
  
  @Autowired
  private JedisCluster jedisCluster;
  /**
   * 实现用户权限认证
   *  1.用户不登陆,不允许访问涉密操作.重定向到
   *  用户登录页面.
   *  2.如果用户登录,则请求予以放行.
   *  
   * 方法说明:
   *  1.boolean  
   *    true: 放行
   *    false: 拦截 配合重定向使用
   * 实现步骤:
   *  1.获取用户的Cookie信息. 获取密钥
   *  2.从redis中获取数据.   
   */
  @Override
  public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
      throws Exception {
    Cookie[] cookies = request.getCookies();
    String ticket = null;
    //判断cookie是有效的.
    if(cookies.length > 0 ) {
      for (Cookie cookie : cookies) {
        if(TICKET.equals(cookie.getName())) {
          ticket = cookie.getValue();
          break;
        }
      }
    }
    
    if(!StringUtils.isEmpty(ticket)) {
      //校验redis中是否有数据
      String userJSON = jedisCluster.get(ticket);
      if(!StringUtils.isEmpty(userJSON)) {
        //实现用户信息的动态获取
        User user = ObjectMapperUtil.toObject(userJSON,User.class);
        request.setAttribute("JT_USER", user);
        UserThreadLocalUtil.set(user);
        return true;
      }
    }
    
    //如果用户没有登录需要重定向到登录页面
    response.sendRedirect("/user/login.html");
    return false; 
  }
  
  
  @Override
  public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
      throws Exception {
    
    //防止内存溢出
    UserThreadLocalUtil.remove();
  }
  
}

其中的UserThreadLocalUtil具体为:

public class UserThreadLocalUtil {
  
  private static 
  ThreadLocal<User> userThread = 
          new ThreadLocal<>();
  
  public static void set(User user) {
    
    userThread.set(user);
  }
  
  public static User get() {
    
    return userThread.get();
  }
  
  public static void remove() {
    
    //防止内存泄漏
    userThread.remove();
  }
}

拦截器配置拦截路径

@Configuration
public class MvcConfigurer implements WebMvcConfigurer{
  
  @Autowired
  private UserInterceptor userInterceptor;
  
  /**
   * 拦截器路径:
   *  /cart/*  拦截url请求中/cart/xxxx 下的一级路径
   *  /cart/** 拦截cart下的所有路径
   */
  @Override
  public void addInterceptors(InterceptorRegistry registry) {
    
    registry.addInterceptor(userInterceptor).addPathPatterns("/cart/**","/order/**");
  }
  
}

退出登录

/**
   * 实现用户登出操作.
   *  0.获取cookie数据
   *  1.删除redis  key~~~ticket
   *  2.删除cookie
   * @return
   */
  @RequestMapping("/logout")
  public String logout(HttpServletRequest request,HttpServletResponse response) {
    Cookie[] cookies = request.getCookies();
    String ticket = null;
    //判断cookie是有效的.
    if(cookies.length > 0 ) {
      for (Cookie cookie : cookies) {
        if(TICKET.equals(cookie.getName())) {
          ticket = cookie.getValue();
          break;
        }
      }
    }
    
    if(!StringUtils.isEmpty(ticket)) {
      //如果数据不为null,则删除数据
      jedisCluster.del(ticket);
      Cookie cookie = new Cookie(TICKET, "");
      cookie.setMaxAge(0); //立即删除
      cookie.setPath("/");
      cookie.setDomain("jt.com");
      response.addCookie(cookie);
    }
    
    //重定向到系统首页
    return "redirect:/"; 
  }

总结

用户登录后,将返回的凭证塞入Cookie返回给浏览器,并且存一份到Redis(凭证作为key,对应的用户信息为value,并设置对应的过期时间),当用户访问其他同后缀的域名时 比如order.jt.com或者cart.jt.com时,浏览器会自动带上之前的Cookie,拦截器中校验Cookie中存的凭证在Redis中查询是否有该用户,有的话放行,没有重定向到登录页面.

相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
目录
相关文章
|
2月前
|
存储 缓存
实现单点登录的方式
实现单点登录的方式
31 1
|
5月前
|
安全 数据安全/隐私保护
单点登录(SSO)看这一篇就够了
单点登录(SSO)看这一篇就够了
212 0
|
安全 数据安全/隐私保护 UED
什么是单点登录(SSO)?底层原理是什么?
什么是单点登录(SSO)?底层原理是什么?
379 0
|
数据安全/隐私保护 UED
SSO的优点是什么?
SSO的优点是什么?
185 0
|
存储 JSON 数据安全/隐私保护
Jasny SSO是如何实现的?底层原理是什么?
Jasny SSO是如何实现的?底层原理是什么?
|
存储 JSON 运维
如何设计一套单点登录系统(上)
昨天介绍了API接口设计token鉴权方案,其实token鉴权最佳的实践场景就是在单点登录系统上。 在企业发展初期,使用的后台管理系统还比较少,一个或者两个。 以电商系统为例,在起步阶段,可能只有一个商城下单系统和一个后端管理产品和库存的系统。
如何设计一套单点登录系统(上)
|
存储 缓存 安全
如何设计一套单点登录系统(下)
昨天介绍了API接口设计token鉴权方案,其实token鉴权最佳的实践场景就是在单点登录系统上。 在企业发展初期,使用的后台管理系统还比较少,一个或者两个。 以电商系统为例,在起步阶段,可能只有一个商城下单系统和一个后端管理产品和库存的系统。
|
存储 安全 Java
单点登录的原理
单点登录的原理
267 0
|
存储 NoSQL 应用服务中间件
SSO单点登录流程源码学习
单点登录系统无状态应用,通过对SSO单点登录系统验证码、LT存入redis,及补偿service的操作更加深入的了解单点登录系统登录流程
SSO单点登录流程源码学习
|
存储 JavaScript 前端开发
单点登录原理及其实现方案
单点登录(Single sign-on,简称 SSO),一种对于许多相互关连,但是又是各自独立的软件系统,提供访问控制的属性。 当拥有该属性时,当用户登录时,就可以获取所有系统的访问权限,不用对每个单一系统都逐一登录。所以你会看到很多域名直接是sso.domain.com,也就是用来做单点登录。
262 0
单点登录原理及其实现方案