美文网首页
SpringBoot系列:2.注册,登录与session

SpringBoot系列:2.注册,登录与session

作者: dothetrick | 来源:发表于2020-11-01 16:59 被阅读0次

    内容概述

    上一篇文章主要说明了,如何用很少的代码,通过SpringBoot的自动配置,实现一个读取数据库并返回数据的简单api。

    实际应用中,一个web服务都会有用户的注册,登录和鉴权等功能。

    这篇文章主要包含这几个功能的简单实现。

    1.注册

    注册的基本实现是接收到用户名和密码,并把密码加密后保存到数据库,实现如下:

    @RestController //定义为rest类型的控制器
    public class UserController {
        @Resource //注入MainUserService
        IMainUserService mainUserService;
    
        @PostMapping("user/register") //定义post请求
        public CommonResVo<Boolean> userRegister(@RequestBody MainUser mainUser) throws Exception {
            //验证用户名是否已存在
            MainUser oldUser = mainUserService.getOne(new LambdaQueryWrapper<MainUser>().eq(MainUser::getUserName, mainUser.getUserName()));
            if (oldUser != null) {
                throw new Exception("用户已存在");
            }
            //用户密码存表时,要做加密处理,可以直接使用spring提供的DigestUtils工具类生成32位MD5字符串
            String password = DigestUtils.md5DigestAsHex(mainUser.getPassword().getBytes());
            mainUser.setPassword(password);
            mainUserService.save(mainUser);
            return CommonResVo.success(true);
        }
    }
    
    • controller的方法中,@RequestBody指定使用post请求在body中发送json格式的数据,spring可以直接将同名参数赋值给MainUser的对象
    • 例如该请求传入的参数如下:
    {
        "userName":"test2",
        "password":"123456",
        "userPhone":"13900010200"
    }
    
    • 程序中获取到的对象为:
    image

    2.登录

    这里使用session作为用户登录后的验证方式,登录成功后会将userId写入session中,生产中的服务基本都是集群的,需要共享session。

    在spring中,可以通过配置session starter,很简单的将session信息存储到redis中。

    • 需要的starter依赖,因为项目中已经引入了spring-boot-starter-parent指定统一版本,所以这里不需要写版本
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>
    
    <dependency>
        <groupId>org.springframework.session</groupId>
        <artifactId>spring-session-data-redis</artifactId>
    </dependency>
    
    • application.yml中需要增加的配置
    spring:
      redis:
        database: 0
        host: localhost
        port: 6379
      session:
        store-type: redis
        timeout: 600s
    
    
    • 完成上面的配置,就可以通过redis在集群中共享session信息了,登录代码如下:
      • 处理Get请求时,可以直接将请求url中的参数赋值给同名的函数参数。该功能主要是通过ParameterNameDiscoverer实现的。
    @GetMapping("user/login")
    public CommonResVo<Boolean> userRegister(String userName, String password, HttpSession session) throws Exception {
        //通过用户名获取用户信息
        MainUser mainUser = mainUserService.getOne(new LambdaQueryWrapper<MainUser>().eq(MainUser::getUserName, userName));
        if (mainUser == null) {
            throw new Exception("用户不存在");
        }
        //对比MD5密码
        String md5Password = DigestUtils.md5DigestAsHex(password.getBytes());
        if (!mainUser.getPassword().equals(md5Password)) {
            throw new Exception("账号名或密码错误");
        }
        //将userId存入session中,这里会存储到redis中
        session.setAttribute("userId", mainUser.getUserId());
        return CommonResVo.success(true);
    }
    

    3.鉴权

    鉴权的过程就是根据请求中的session信息,获取userId,可以获取到,证明已登录,后续根据userId获取用户信息进行逻辑处理。

    获取不到,说明已过期或未登录,提示重新登录。

    web服务中,大部分接口都需要鉴权,这里使用拦截器实现。

    通过实现HandlerInterceptor接口定义一个拦截器,然后添加到web流程中,代码如下:

    • 拦截器实现
    public class LoginAuthInterceptor implements HandlerInterceptor {
    
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            //这里实际是从redis中获取到session信息
            HttpSession session = request.getSession();
            Integer userId = (Integer) session.getAttribute("userId");
            if (userId == null) {
                authFailOutput(response, "登录信息不存在,请重新登录");
                return false;
            }
            return true;
        }
    
        /**
         * json输出
         *
         * @param response
         * @throws IOException
         */
        private void authFailOutput(HttpServletResponse response, String msg) throws IOException {
            response.setContentType("application/json;charset=UTF-8");
            PrintWriter out = response.getWriter();
            ObjectMapper objectMapper = new ObjectMapper();
            out.write(objectMapper.writeValueAsString(CommonResVo.fail(400, msg)));
            out.flush();
        }
    }
    
    • 将自定义拦截器添加到web mvc中,这里可以添加多个拦截器,每个拦截器可以设置不同的拦截策略:
    @Configuration
    public class Interceptor implements WebMvcConfigurer {
    
        @Bean
        LoginAuthInterceptor loginAuthInterceptor() {
            return new LoginAuthInterceptor();
        }
    
        @Override
        public void addInterceptors(InterceptorRegistry registry) {
            // 添加一个拦截器,排除登录url
            registry.addInterceptor(loginAuthInterceptor())
                    .excludePathPatterns("/user/login");
        }
    }
    

    通常创建session后,sessionId会保存在cookies里面,默认名是SESSION,用于之后的每次请求。这里要注意,cookies保存的sessionId默认是base64编码过的,所以和程序中使用session.getId()获取到的会不同。

    3.1 自定义sessionId

    如果不想使用系统默认的cookie名称保存sessionId,可以通过修改application.yml的配置实现自定名称,示例如下:

    server:
      port: 8999
      servlet:
        session:
          cookie:
            name: myjsessionid //自定义的session名称
    

    这样系统中就会使用myjsessionid保存和解析session信息。

    源码地址:https://gitee.com/dothetrick/web-demo/tree/register-login/

    以上内容属个人学习总结,如有不当之处,欢迎在评论中指正

    相关文章

      网友评论

          本文标题:SpringBoot系列:2.注册,登录与session

          本文链接:https://www.haomeiwen.com/subject/btcuvktx.html