0.前言

这里省略介绍redis的基本概念,和使用redis储存用户登录信息的好处。
原料:已经引入redis的java项目,(框架无所谓,我这里是springboot)

1.几个初始的步骤

1.1 确定好前台传输的,请求头上的登录标识
这里我使用的是“sessionId”
1.2 定义储存用户信息的类,方便redis做存储
@Data
public class SessionUser implements Serializable {
    //session用户数据的类型(默认为 A,SessionTypeUtil)
    private String sessionType;

    //用户id
    private Long userId;
    //手机号
    private String phone;
    //名字
    private String name;
}
1.3 初始化redis的方法,这里只需要用到最基础的 get、set方法

2.确定本次登录架构的整体逻辑

一次请求的代码逻辑拓扑图

在这里插入图片描述

3.代码逻辑的编写

3.1 用户信息储存到redis(登录接口)
 	@GetMapping(value = "/login", produces = "application/json;charset=UTF-8")
    @ApiOperation(value = "手机号登录", httpMethod = "GET", produces = "application/json;charset=UTF-8")
    @ApiResponse(code = 200, message = "Ok", response = Result.class)
    @ApiImplicitParams({
            @ApiImplicitParam(name = "phone", value = "phone", required = true, paramType = "query"),
            @ApiImplicitParam(name = "password", value = "password", required = true, paramType = "query")
    })
    public Result<Object> login(String phone, String password) {
    	//注意:这里只做简单的登录校验,删除了验证码及密码加密的逻辑
    	
    	//mybatisPlus的写法
        Wrapper<UserIndex> wrapper = new EntityWrapper<>();
        wrapper.eq("phone", phone);
        wrapper.eq("password", password); 
        List<UserIndex> userIndices = userIndexService.selectList(wrapper);
        if (userIndices.size() == 1) {
            UserIndex userIndex = userIndices.get(0);
            SessionUser sessionUser = new SessionUser();
            sessionUser.setUserId(userIndex.getId());
            sessionUser.setPhone(userIndex.getPhone());
            sessionUser.setName(userIndex.getName());
            sessionUser.setSessionType(SessionTypeUtil.INDEX_USER);
            String sessionId = SessionIdUtil.getSessionId();
            //登录时 redis存储一个sessionId 和 用户的注册信息
            sessionManager.setSession(sessionId, sessionUser); 
            
            logger.info(sessionUser.getPhone() + ":登录成功,sessionId:" + sessionId);
            return response("登录成功,sessionId:" + sessionId);
        } else {
            throw new Exception("手机号或密码错误!");
        }
    }
3.2 接口获取用户信息的方式
	从以上的拓扑图可以看出,当用户成功登录,前端得到用户的登录标识(sessionId)后,我们就能通过指定的代码逻辑获取用户的登录信息,并返回用户想要的内容。
	经分析,得出因为每个接口都要面对进行登录的校验,所以我们把拓扑图的实现代码放在Filter中最为合适。
@Slf4j
@Component
public class SessionFilter implements Filter {

    /**
     * 这里只是写了 doFilter 的方法实现
     */
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) request;
        HttpServletResponse res = (HttpServletResponse) response;
        String requestURI = ((HttpServletRequest) request).getRequestURI();
        String sessionId = req.getHeader("sessionId"); //获取sessionId
        try {
            SessionUser sessionUser;

            if (是否为不用登录的接口) {
                //1.是 不用登录的接口
                chain.doFilter(request, response);
                return;
            } else {
            	//2.不是 需要登录
                try {
                    //查询登录信息
                    sessionUser = getSessionUser(sessionId);//(获取用户信息的方法,获取不到抛出异常)
                    //延长sessionTime
                    sessionManager.setSession(sessionId, sessionUser);
                } catch (Exception e) {
                    //登录信息获取失败 getSessionUser(抛出异常了)
                    if (是否为非强制登录的接口) {
                        //是非强制登录的接口
                        sessionUser = null;
                    } else {
                        throw e;
                    }
                }
            }

            //将取出的用户信息写入当前线程
            sessionManager.setCurrent(sessionUser);
            //先进行接口中数据逻辑的运行(中间应该会拿取线程中的登录信息)
            chain.doFilter(request, response);
            //再把 当前线程存储的用户信息清空
            sessionManager.clear();
        } catch (SessionException e) {
            String code = 502;
            
            log.debug(String.format("sessionId: %s, msg: %s", sessionId, e.getMessage()));
            res.setContentType("application/json;charset=UTF-8");
            res.setHeader("Access-Control-Allow-Origin", "*");
            res.getWriter().write(JSON.toJSONString(new Result<>(code, e.getMessage(), "")));
            res.getWriter().close();
            return;
        }
    }
}
3.3 使用用户数据
	至此我们已经将获取到的用户信息写入本次线程中,等到接口中要使用用户信息就从当前线程中取就行。
3.4 注意事项
	(1)因为将用户信息写进了线程,故退出登录时一定记得清除当前线程中的用户信息。
	(2)为了便于扩展,我们在储存用户信息的类中预留了sessionType字段,对于不太复杂的系统,可以尝试用一个sessionUser类存储前后台,多个账户类型的信息。
Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐