登录接口
@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中查询是否有该用户,有的话放行,没有重定向到登录页面.