欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

SpringBoot+JWT實現(xiàn)注冊、登錄、狀態(tài)續(xù)簽流程分析

 更新時間:2022年06月09日 11:48:47   作者:什么都干的派森  
這篇文章主要介紹了SpringBoot+JWT實現(xiàn)注冊、登錄、狀態(tài)續(xù)簽【登錄保持】,本文通過示例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下

一、實現(xiàn)流程

1.注冊

2.登錄

3.登錄保持【狀態(tài)續(xù)簽】

二、實現(xiàn)方法

項目結(jié)構(gòu)

1.引入依賴

<!-- spring-web -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- mysql連接器 -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- Mybatis Plus -->
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.4.3.4</version>
</dependency>
<!-- druid -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid-spring-boot-starter</artifactId>
    <version>1.2.8</version>
</dependency>
<!-- jwt -->
<dependency>
    <groupId>com.auth0</groupId>
    <artifactId>java-jwt</artifactId>
    <version>3.10.3</version>
</dependency>

2.application配置文件

spring:
  application:
    name: jwtLogin   # 應(yīng)用名稱
  datasource:
    druid:
      url: jdbc:mysql://192.168.0.111:3306/login_test?useSSL=false&serverTimezone=UTC
      username: samon
      password: 123456
      driver-class-name: com.mysql.jdbc.Driver
server:
  port: 8848   # 應(yīng)用服務(wù) WEB 訪問端口

3.mysql建表

用戶表

4.Bean

1.bean/user.java
用戶bean

package com.cxstar.bean;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;
import java.util.Date;
@Data
public class User {
    // 自增長id
    @TableId(type = IdType.AUTO)
    private Integer id;
    private String userName;
    private String passWord;
    private Date createTime;
    private Date lastLogin;
    public  User() {}
    public User(Integer id, String userName) {
        this.id = id;
        this.userName = userName;
    }
}

2.bean/ServiceRes.java
統(tǒng)一Service返回類

package com.cxstar.bean;
import lombok.Data;
@Data
public class ServiceRes {
    private Integer code;
    private String msg;
    private String jwt;
    private ServiceRes() {}
    public ServiceRes(Integer code, String msg) {
        this.code = code;
        this.msg = msg;
    }
    public ServiceRes(Integer code, String msg, String jwt) {
        this.code = code;
        this.msg = msg;
        this.jwt = jwt;
    }
}

3.bean/ControllerRes.java
統(tǒng)一Controller返回類

package com.cxstar.bean;
import lombok.Data;
@Data
public class ControllerRes {
    private Integer code;
    private String msg;
    public ControllerRes(Integer code, String msg) {
        this.code = code;
        this.msg = msg;
    }
}

5.Mapper mapper/UserMapper.java
繼承MP

package com.cxstar.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.cxstar.bean.User;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface UserMapper extends BaseMapper<User> {
}

6.service service.userService.interface
登錄、注冊、改密業(yè)務(wù)【狀態(tài)續(xù)簽測試】

package com.cxstar.service;
import com.cxstar.bean.ServiceRes;
import com.cxstar.bean.User;
public interface userService {
    // 注冊
    ServiceRes register(User user);
    // 登錄
    ServiceRes login(User user);
    // 改密【帶權(quán)限業(yè)務(wù),用于狀態(tài)續(xù)簽測試】
    ServiceRes changePassWord(User user);
}

service.impl.UserServiceImpl.java
登錄、注冊、改密業(yè)務(wù)【狀態(tài)續(xù)簽測試】

package com.cxstar.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.cxstar.bean.ServiceRes;
import com.cxstar.bean.User;
import com.cxstar.mapper.UserMapper;
import com.cxstar.service.userService;
import com.cxstar.utils.JwtUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;
import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Slf4j
@Service
public class UserServiceImpl implements userService {
    @Autowired
    UserMapper userMapper;
    /**
     * 注冊
     * @param user 用戶類
     * @return ServiceRes
     */
    @Override
    public ServiceRes register(User user) {
        // 判斷用戶名是否唯一
        if(this.checkUserNameIsUnique(user)) {
            // 判斷用戶名密碼是否合法
            if(this.checkUserNameAndPassword(user)) {
                // 密碼MD5加密
                user.setPassWord(this.MD5Code(user.getPassWord()));
                // 加入創(chuàng)建時間
                user.setCreateTime(new Date());
                // 入庫
                userMapper.insert(user);
                return new ServiceRes(1, "注冊成功");
            } else return new ServiceRes(-1, "用戶名或密碼不合法");
        } else return new ServiceRes(-1, "用戶名已存在");
    }
    /**
     * 登錄
     * @param user 用戶類
     * @return ServiceRes
     */
    @Override
    public ServiceRes login(User user) {
        // 判斷用戶名密碼是否合法
        if(this.checkUserNameAndPassword(user)) {
            // 密碼MD5加密
            user.setPassWord(this.MD5Code(user.getPassWord()));
            // 檢查用戶是否存在
            User curUser = this.checkUserIsExit(user);
            if(curUser!=null) {
                // 更新用戶最后登錄時間
                curUser.setLastLogin(new Date());
                userMapper.updateById(curUser);
                // 生成jwt
                Map<String, String> payload = new HashMap<>();
                payload.put("userId", curUser.getId().toString()); // 加入一些非敏感的用戶信息
                payload.put("userName", curUser.getUserName());    // 加入一些非敏感的用戶信息
                String jwt = JwtUtil.generateToken(payload);
                return new ServiceRes(1, "登錄成功", jwt);
            } else return new ServiceRes(-1, "用戶名或密碼錯誤");
        } else return new ServiceRes(-1, "用戶名或密碼不合法");
    }
    /**
     * 改密業(yè)務(wù)
     * @return ServiceRes
     */
    @Override
    public ServiceRes changePassWord(User user) {
        if(this.updatePassWord(user)) return new ServiceRes(1, "改密成功");
        else return new ServiceRes(-1, "改密失敗");
    }
    /**
     * 非對稱加密
     * @param text 明文
     * @return 密文
     */
    private String MD5Code(String text) {
        return DigestUtils.md5DigestAsHex(text.getBytes(StandardCharsets.UTF_8));
    }
    /**
     * 修改密碼方法
     * @param user 傳入用戶名和新密碼
     * @return 改密成功返回 true 失敗返回 false
     */
    private Boolean updatePassWord(User user) {
        // 密碼非對稱加密
        user.setPassWord(this.MD5Code(user.getPassWord()));
        // 更新密碼
        return userMapper.updateById(user)>0;
    }
    /**
     * 檢查用戶是否存在【用戶名密碼相同】
     * @param user 用戶類
     * @return 用戶存在返回 用戶對象 不存在返回 null
     */
    private User checkUserIsExit(User user) {
        LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<>();
        lqw.eq(User::getUserName, user.getUserName());
        lqw.eq(User::getPassWord, user.getPassWord());
        return userMapper.selectOne(lqw);
    }
    /**
     * 判斷用戶名是否唯一
     * @param user 用戶類
     * @return 唯一返回 true 不唯一返回 false
     */
    private Boolean checkUserNameIsUnique(User user) {
        LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<>();
        lqw.eq(User::getUserName, user.getUserName());
        List<User> userList = userMapper.selectList(lqw);
        return userList.size() == 0;
    }
    /**
     * 判斷用戶名密碼是否合法
     * @param user 用戶類
     * @return 滿足 【英文字母、數(shù)字、下劃線】 返回 true,否則返回 false
     */
    private Boolean checkUserNameAndPassword(User user) {
        String regex = "^[_a-z0-9A-Z]+$";
        return user.getUserName().matches(regex) && user.getPassWord().matches(regex);
    }

}

6.Controller controller/UserController.java
登錄、注冊、改密業(yè)務(wù)【狀態(tài)續(xù)簽測試】

package com.cxstar.controller;
import com.cxstar.bean.ControllerRes;
import com.cxstar.bean.ServiceRes;
import com.cxstar.bean.User;
import com.cxstar.service.userService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Slf4j
@Controller
@ResponseBody
@RequestMapping("/user")
public class UserController {
    @Autowired
    userService userService;
    @PostMapping("/register")
    public ControllerRes register(User user) {
        // 注冊
        ServiceRes serviceRes = userService.register(user);
        return new ControllerRes(serviceRes.getCode(), serviceRes.getMsg());
    }
    @PostMapping("/login")
    public ControllerRes login(User user, HttpServletResponse response) {
        // 登錄
        ServiceRes serviceRes = userService.login(user);
        // 登錄成功后往響應(yīng)頭插入jwt
        if(serviceRes.getJwt() != null) response.addHeader("access-token", serviceRes.getJwt());
        return new ControllerRes(serviceRes.getCode(), serviceRes.getMsg());
    }
    @PutMapping("/pwd")
    public ControllerRes changePassWord(User user, HttpServletRequest request) {
        // 取出jwt中的用戶
        User jwtUser = (User)request.getAttribute("jwt-user");
        // 合并jwt中用戶的用戶名與傳入用戶的新密碼
        // 此處不能直接使用傳入的用戶名,防止惡意修改其他用戶的密碼
        user.setId(jwtUser.getId());
        // 改密
        ServiceRes serviceRes = userService.changePassWord(user);
        return new ControllerRes(serviceRes.getCode(), serviceRes.getMsg());
    }
}

7.JWT工具類 utils/JwtUtil.java
生成和解析 token 的方法

package com.cxstar.utils;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTCreator;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.auth0.jwt.interfaces.JWTVerifier;
import java.util.Calendar;
import java.util.Date;
import java.util.Map;
public class JwtUtil {
    // 簽名密鑰
    private static final String SECRET = "hello JWT *%$#$&";
    /**
     * 生成token
     * @param payload token攜帶的信息
     * @return token字符串
     */
    public static String generateToken(Map<String,String> payload){
        // 指定token過期時間
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.HOUR, 24);  // 24小時
        JWTCreator.Builder builder = JWT.create();
        // 構(gòu)建payload
        payload.forEach(builder::withClaim);
        // 指定簽發(fā)時間、過期時間 和 簽名算法,并返回token
        String token = builder.withIssuedAt(new Date()).withExpiresAt(calendar.getTime()).sign(Algorithm.HMAC256(SECRET));
        return token;
    }

    /**
     * 解析token
     * @param token token字符串
     * @return 解析后的token類
     */
    public static DecodedJWT decodeToken(String token){
        JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(SECRET)).build();
        DecodedJWT decodedJWT = jwtVerifier.verify(token);
        return decodedJWT;
    }
}

8.HandlerInterceptor攔截器 interceptor.java
攔截器業(yè)務(wù)實現(xiàn)

package com.cxstar.interceptor;

import com.alibaba.fastjson.JSONObject;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.exceptions.TokenExpiredException;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.cxstar.bean.ControllerRes;
import com.cxstar.bean.User;
import com.cxstar.utils.JwtUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * 攔截需要授權(quán)的接口
 */
@Slf4j
public class PermisssionInterceptor implements HandlerInterceptor {

    // 目標(biāo)方法執(zhí)行前調(diào)用
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws IOException {

        // 檢查用戶JWT
        String jwt = request.getHeader("access-token");

        // 校驗并取出私有信息
        try {

            // token 解碼
            DecodedJWT dj = JwtUtil.decodeToken(jwt);

            // 取出基本用戶信息加入請求頭 --------------------------------------------------------------------------------
            String userId = dj.getClaim("userId").asString();
            String userName = dj.getClaim("userName").asString();
            // jwt校驗合格的,將 jwt 中存的用戶信息加入請求頭,不合格的,請求頭存?zhèn)€空用戶
            request.setAttribute("jwt-user", userId!=null?new User(Integer.valueOf(userId), userName):new User());
            // -------------------------------------------------------------------------------------------------------

            // 計算當(dāng)前時間是否超過過期時間的一半,如果是就幫用戶續(xù)簽 --------------------------
            // 此處并不是永久續(xù)簽,只是為 大于過期時間的一半 且 小于過期時間 的 token 續(xù)簽
            Long expTime = dj.getExpiresAt().getTime();
            Long iatTime = dj.getIssuedAt().getTime();
            Long nowTime = new Date().getTime();
            if((nowTime-iatTime) > (expTime-iatTime)/2) {
                // 生成新的jwt
                Map<String, String> payload = new HashMap<>();
                payload.put("userId", userId); // 加入一些非敏感的用戶信息
                payload.put("userName", userName);    // 加入一些非敏感的用戶信息
                String newJwt = JwtUtil.generateToken(payload);
                // 加入返回頭
                response.addHeader("access-token", newJwt);
            }
            // -----------------------------------------------------------------------

            return true;

        } catch (JWTDecodeException e) {
            log.error("令牌錯誤");
            addResBody(response, new ControllerRes(-1, "令牌錯誤"));  // 新增返回體
            return false;

        } catch (TokenExpiredException e) {
            log.error("令牌過期");
            addResBody(response, new ControllerRes(-1, "令牌過期"));  // 新增返回體
            return false;
        }

    }

    // 目標(biāo)方法執(zhí)行后調(diào)用
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
    }

    // 頁面渲染前調(diào)用
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
    }

    private void addResBody(HttpServletResponse response, ControllerRes res) throws IOException {

        response.setStatus(HttpServletResponse.SC_FORBIDDEN);        // 設(shè)置狀態(tài)碼

        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json; charset=utf-8");
        PrintWriter out = response.getWriter();
        out.write(JSONObject.toJSONString(res));
        out.flush();
        out.close();

    }

}

config/PermissionWebConfig.java
攔截器攔截規(guī)則

package com.cxstar.config;
import com.cxstar.interceptor.PermisssionInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class PermissionWebConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new PermisssionInterceptor())
                .addPathPatterns("/**")    // 攔截哪些頁面
                .excludePathPatterns("/user/login", "/user/register");   // 放行哪些頁面
    }
}

三、測試

1.注冊

注冊成功

數(shù)據(jù)入庫

2.登錄

登錄成功

查看登錄后返回的token

3.狀態(tài)續(xù)簽【登錄保持】

使用上一步登錄返回的 token 請求改密業(yè)務(wù)

當(dāng) JWT 存在時間小于 JWT 過期時間的一半時
業(yè)務(wù)會執(zhí)行成功
執(zhí)行業(yè)務(wù)不會返回續(xù)簽的 token

當(dāng) JWT 存在時間大于 JWT 過期時間的一半 且 小于過期時間 時
業(yè)務(wù)會執(zhí)行成功
執(zhí)行業(yè)務(wù)會返回續(xù)簽的 token,前端的下次請求需要使用新續(xù)簽的 token

當(dāng) JWT 存在時間大于 JWT 過期時間 時
業(yè)務(wù)會執(zhí)行失敗
執(zhí)行業(yè)務(wù)不會返回續(xù)簽的 token

到此這篇關(guān)于SpringBoot+JWT實現(xiàn)注冊、登錄、狀態(tài)續(xù)簽的實戰(zhàn)教程的文章就介紹到這了,更多相關(guān)SpringBoot JWT登錄狀態(tài)續(xù)簽內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java中方法作為參數(shù)傳遞的方式

    Java中方法作為參數(shù)傳遞的方式

    這篇文章主要介紹了Java如何讓方法作為參數(shù)傳遞,本文通過實例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-05-05
  • Java判斷數(shù)字位數(shù)的方法總結(jié)

    Java判斷數(shù)字位數(shù)的方法總結(jié)

    本文給大家整理了Java判斷數(shù)字位數(shù)的兩種常用方法,對此有興趣的可以跟著小編一起學(xué)習(xí)下。
    2018-02-02
  • Java并發(fā)編程中的synchronized關(guān)鍵字詳細(xì)解讀

    Java并發(fā)編程中的synchronized關(guān)鍵字詳細(xì)解讀

    這篇文章主要介紹了Java并發(fā)編程中的synchronized關(guān)鍵字詳細(xì)解讀,在Java早期版本中,synchronized 屬于 重量級鎖,效率低下,這是因為監(jiān)視器鎖(monitor)是依賴于底層的操作系統(tǒng)的Mutex Lock來實現(xiàn)的,Java 的線程是映射到操作系統(tǒng)的原生線程之上的,需要的朋友可以參考下
    2023-12-12
  • SpringBoot+layuimini實現(xiàn)左側(cè)菜單動態(tài)展示的示例代碼

    SpringBoot+layuimini實現(xiàn)左側(cè)菜單動態(tài)展示的示例代碼

    Layuimini是Layui的升級版,它是專業(yè)做后臺頁面的框架,而且是適合PC端和移動端,以下地址可以在PC端顯示,也可以在手機上顯示,只不過會做自適應(yīng),本文將給大家介紹了SpringBoot+layuimini實現(xiàn)左側(cè)菜單動態(tài)展示的方法,需要的朋友可以參考下
    2024-04-04
  • Spring Boot報錯:No session repository could be auto-configured, check your configuration的解決方法

    Spring Boot報錯:No session repository could be auto-configured

    這篇文章主要給大家介紹了關(guān)于Spring Boot報錯:No session repository could be auto-configured, check your configuration的解決方法,文中給出了詳細(xì)的解決方法,對遇到這個問題的朋友們具有一定參考價值,需要的朋友下面來一起看看吧。
    2017-07-07
  • java設(shè)計模式之裝飾器模式(Decorator)

    java設(shè)計模式之裝飾器模式(Decorator)

    這篇文章主要為大家詳細(xì)介紹了java設(shè)計模式之裝飾器模式Decorator,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-01-01
  • 一文搞懂如何實現(xiàn)Java,Spring動態(tài)啟停定時任務(wù)

    一文搞懂如何實現(xiàn)Java,Spring動態(tài)啟停定時任務(wù)

    定時任務(wù)的應(yīng)用場景十分廣泛,如定時清理文件、定時生成報表、定時數(shù)據(jù)同步備份等。本文將教你實現(xiàn)Java、Spring動態(tài)啟停定時任務(wù),感興趣的可以學(xué)習(xí)一下
    2022-06-06
  • 基于Java回顧之JDBC的使用詳解

    基于Java回顧之JDBC的使用詳解

    本篇文章是對Java中JDBC的使用進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下
    2013-05-05
  • Java雇員管理小項目

    Java雇員管理小項目

    這篇文章主要為大家詳細(xì)介紹了Java雇員管理小項目,理解面向?qū)ο缶幊蹋哂幸欢ǖ膮⒖純r值,感興趣的小伙伴們可以參考一下
    2018-01-01
  • 簡單了解springboot eureka交流機制

    簡單了解springboot eureka交流機制

    這篇文章主要介紹了簡單了解springboot eureka交流機制,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-04-04

最新評論