SpringBoot使用redis做分布式Session

1. 核心原理

主要是通过redis,当用户登录后生成一个随机的uuid作为token,将token作为键,user对象作为值存储到redis数据库中,同时将token保存到cookie中 ,当访问其他页面时判断cookie中是否有token,如果有,则根据此token从redis拿到用户信息即可。

关于springboot 操作redis方面请查看 : https://blog.youkuaiyun.com/junmoxi/article/details/80694405

2. User服务类

package com.pibigstar.springboot.service.impl;

import java.util.UUID;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import com.pibigstar.springboot.dao.JPADao;
import com.pibigstar.springboot.domain.User;
import com.pibigstar.springboot.service.RedisService;
import com.pibigstar.springboot.service.UserService;

@Service
public class UserServiceImpl implements UserService{

    public static final String COOKIE_USER_TOKEN = "token";
    public static final int COOKIE_TOKEN_TIMEOUT = 3600*24*2;//两天

    @Autowired
    private RedisService redisService;

    /**
     * 登录
     * @param response
     * @param loginVo
     * @return
     */
    @Override
    public boolean login(HttpServletResponse response, LoginVo loginVo) {
        if(loginVo == null) {
            throw new GlobalException(CodeMsg.SERVER_ERROR);
        }
        String mobile = loginVo.getMobile();
        String formPass = loginVo.getPassword();
        //判断手机号是否存在
        User user = getById(Long.parseLong(mobile));
        if(user == null) {
            throw new GlobalException(CodeMsg.MOBILE_NOT_EXIST);
        }
        //验证密码
        String dbPass = user.getPassword();
        String saltDB = user.getSalt();
        String calcPass = MD5Util.formPassToDBPass(formPass, saltDB);
        if(!calcPass.equals(dbPass)) {
            throw new GlobalException(CodeMsg.PASSWORD_ERROR);
        }
        //生成cookie
        String token = UUID.randomUUID().toString().replace("-", "");
        addCookie(response, token, user);
        return true;
    }

    /**
     * 根据token从redis中拿到user对象
     */
    @Override
    public User getByToken(HttpServletResponse response, String token) {
        if (token==null) {
            return null;
        }
        User user = (User) redisService.getObject(token);
        if (user!=null) {
            //延长cookie有效期
            addCookie(response,token,user);
        }
        return user;

    }

    /**
     * 将token放到cookie中
     * @param response
     * @param token
     * @param user
     */
    private void addCookie(HttpServletResponse response, String token, User user) {
        redisService.setObject(token, user,COOKIE_TOKEN_TIMEOUT);
        Cookie cookie = new Cookie(COOKIE_USER_TOKEN, token);
        //设置cookie有效期
        cookie.setMaxAge(COOKIE_TOKEN_TIMEOUT);
        cookie.setPath("/");
        response.addCookie(cookie);
    }
}

3. 读取cookie中的token

我们通过实现 HandlerMethodArgumentResolver 接口,重写里面的方法,将cookie中或者parameter中的token数据拿到然后查询出user注入到Controller中 的方法参数中

注册一个ArgumentResolvers

package com.pibigstar.springboot.config;

import java.util.List;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebConfig implements WebMvcConfigurer{
    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
        resolvers.add(new UserArgumentResolver());
        WebMvcConfigurer.super.addArgumentResolvers(resolvers);
    }

具体实现类

package com.pibigstar.springboot.config;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.MethodParameter;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;
import org.thymeleaf.util.StringUtils;

import com.pibigstar.springboot.domain.User;
import com.pibigstar.springboot.service.UserService;
import com.pibigstar.springboot.service.impl.UserServiceImpl;
/**
 * 拿到session或parameter中的token
 * 通过token拿到redis中的user
 * 将user注入到方法的参数中
 * @author pibigstar
 *
 */
@Component
public class UserArgumentResolver implements HandlerMethodArgumentResolver{

    @Autowired
    private UserService userService;
    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        Class<?> parameterType = parameter.getParameterType();
        return parameterType==User.class;
    }

    @Override
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
            NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {

        HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
        HttpServletResponse response = webRequest.getNativeResponse(HttpServletResponse.class);

        String cookieToken = getCookieToken(request,UserServiceImpl.COOKIE_USER_TOKEN);
        String parameterToken = request.getParameter(UserServiceImpl.COOKIE_USER_TOKEN);

        if (StringUtils.isEmpty(parameterToken) && StringUtils.isEmpty(cookieToken)) {
            return null;
        }
        String token = StringUtils.isEmpty(parameterToken)?cookieToken:parameterToken;

        return userService.getByToken(response,token);
    }

    private String getCookieToken(HttpServletRequest request,String cookieName) {
        Cookie[] cookies = request.getCookies();
        for (Cookie cookie : cookies) {
            if (cookie.getName().equals(cookieName)) {
                return cookie.getValue();
            }
        }
        return null;
    }

}

4. 使用

package com.pibigstar.springboot.web;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;

import com.pibigstar.springboot.domain.User;

@Controller
public class UserController {

    /**
     * 这里的user 是通过token从redis拿到的
     * 具体实现在UserArgumentResolver中
     */
    public String index(User user,Model model) {
        if(user==null) {
            return "login";
        }else {
            model.addAttribute("user",user);
            return "index";
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值