SpringBoot系列:2.註冊,登陸與session

內容概述

上一篇文章主要說明了,如何用不多的代碼,經過SpringBoot的自動配置,實現一個讀取數據庫並返回數據的簡單api。java

實際應用中,一個web服務都會有用戶的註冊,登陸和鑑權等功能。git

這篇文章主要包含這幾個功能的簡單實現。web

1.註冊

註冊的基本實現是接收到用戶名和密碼,並把密碼加密後保存到數據庫,實現以下:redis

@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

在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信息了,登陸代碼以下:json

    • 處理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獲取用戶信息進行邏輯處理。api

獲取不到,說明已過時或未登陸,提示從新登陸。cookie

web服務中,大部分接口都須要鑑權,這裏使用攔截器實現。session

經過實現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/...

以上內容屬我的學習總結,若有不當之處,歡迎在評論中指正

相關文章
相關標籤/搜索