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

内容概述

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

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

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

1.注册

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

@RestController //定义为rest类型的控制器
public class UserController {
    @Resource //注入MainUserService
    IMainUserService mainUserService;

    @PostMapping("user/register") //定义post请求
    public CommonResVo userRegister(@RequestBody MainUser mainUser) throws Exception {
        //验证用户名是否已存在
        MainUser oldUser = mainUserService.getOne(new LambdaQueryWrapper().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指定统一版本,所以这里不需要写版本

    org.springframework.boot
    spring-boot-starter-data-redis



    org.springframework.session
    spring-session-data-redis

  • 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 userRegister(String userName, String password, HttpSession session) throws Exception {
    //通过用户名获取用户信息
    MainUser mainUser = mainUserService.getOne(new LambdaQueryWrapper().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)