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