栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

spring boot jwt完整过程

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

spring boot jwt完整过程

首先源码https://gitee.com/mobile191llx/spring-boot-jwt.git 接着项目目录结构

项目开始 1.新建项目名称为demo、选择maven什么都不要勾选 2.依赖pom.xml


    4.0.0
    
        org.springframework.boot
        spring-boot-starter-parent
        2.7.2
         
    
    com.example
    demo
    0.0.1-SNAPSHOT
    demo
    Demo project for Spring Boot
    
        1.8
    
    
        
            org.springframework.boot
            spring-boot-starter-web
        
        
            org.mybatis.spring.boot
            mybatis-spring-boot-starter
            2.2.2
        

        
            mysql
            mysql-connector-java
            runtime
        
        
            org.springframework.boot
            spring-boot-starter-test
            test
        
        
            junit
            junit
            test
        
        
            com.auth0
            java-jwt
            3.10.3
        
        
            com.alibaba
            fastjson
            1.2.73
        
    

    
        
            
                org.springframework.boot
                spring-boot-maven-plugin
            
        
    
    
    
        
            aliyun
            https://maven.aliyun.com/repository/public
            
                true
            
            
                false
            
        
    
    
        
            aliyun-plugin
            https://maven.aliyun.com/repository/public
            
                true
            
            
                false
            
        
    


3.新建数据库
create database store; # 新建数据库
use store; # 选中数据库
create table t_user(   # 新建数据表
	uid varchar(50) not null primary key,
    username varchar(20) not null unique,
    password char(50) not null,
    salt varchar(50),
    phone varchar(11) unique,
    email varchar(30) unique not null,
    gender int(1),
    avatar varchar(50),
    is_delete int(1) not null,
    created_user varchar(20) not null,
    created_time datetime not null,
    modified_user varchar(20) not null,
    modified_time datetime not null
)ENGINE=InnoDB DEFAULT CHARSET=utf8;
4.配置项目application.yml
spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver   # 驱动
    username: root     #数据库登录名
    password: 123456   #数据库密码
	# 数据库名为store,字符集为utf-8,时区为北京
    url: jdbc:mysql://localhost:3306/store?characterEncoding=utf-8&serverTimezone=GMT%2B8
mybatis:
  mapper-locations: classpath:mapper
    Integer insert(User user);

    
    User findByUsername(String username);

    Integer updatePasswordByUid(@Param("uid") String uid,
                                @Param("password") String password,
                                @Param("modifiedUser") String modifiedUser,
                                @Param("modifiedTime") Date modifiedTime);

    
    User findByUid(String uid);


}

7 .创建demo/service/ex目录、在ex目录下新建ServiceException异常类
package com.example.demo.Service.ex;


public class ServiceException extends RuntimeException {
    public ServiceException() {
        super();
    }

    public ServiceException(String message) {
        super(message);
    }

    public ServiceException(String message, Throwable cause) {
        super(message, cause);
    }

    public ServiceException(Throwable cause) {
        super(cause);
    }

    protected ServiceException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
        super(message, cause, enableSuppression, writableStackTrace);
    }
}

8.创建demo/service/ex目录、在ex目录下新建5个异常类-InsertException、PasswordNotMatchException、UpdateException、UsernameDuplicatedException、UserNotFoundException,这几个类全部继承上面创建的ServiceException类并且insert+alt选择Override Methods选择前4项,大概如下
package com.example.demo.Service.ex;

public class InsertException extends ServiceException {
    public InsertException() {
        super();
    }

    public InsertException(String message) {
        super(message);
    }

    public InsertException(String message, Throwable cause) {
        super(message, cause);
    }

    public InsertException(Throwable cause) {
        super(cause);
    }

    protected InsertException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
        super(message, cause, enableSuppression, writableStackTrace);
    }
}

9.在service目录下新建IUserService接口
package com.example.demo.Service;

import com.example.demo.entity.User;

public interface IUserService {
    
    void reg(User user);

    
    User login(String username,String password);

    
    void changePassword(String uid, String username, String oldPassword, String newPassword);

	
    User findByUid(String uid);
}

10.在service目录下创建UserServiceImpl
package com.example.demo.Service.impl;

import com.example.demo.Service.IUserService;
import com.example.demo.Service.ex.PasswordNotMatchException;
import com.example.demo.Service.ex.UpdateException;
import com.example.demo.Service.ex.UserNotFoundException;
import com.example.demo.Service.ex.UsernameDuplicatedException;
import com.example.demo.entity.User;
import com.example.demo.mapper.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;

import java.util.Date;
import java.util.UUID;

@Service
public class UserServiceImpl implements IUserService {
    @Autowired
    private UserMapper userMapper;

    @Override
    public void reg(User user) { // 用户注册
        // 查重
        User result = userMapper.findByUsername(user.getUsername());
        if (result != null) {
            throw new UsernameDuplicatedException("用户名被占用");
        }
        // 设置id
        user.setUid(UUID.randomUUID().toString().toUpperCase());
        //  设置初始值
        user.setIsDelete(0);
        user.setCreatedUser(user.getUsername());
        user.setModifiedUser(user.getUsername());
        // 时间
        Date date = new Date();
        user.setModifiedTime(date);
        user.setCreatedTime(date);
        // 密码加密
        String oldPassword = user.getPassword();
        String salt = UUID.randomUUID().toString().toUpperCase();
        String md5Password = getMd5Pw(oldPassword, salt);
        // 保存密码
        user.setPassword(md5Password);
        // 保存盐值
        user.setSalt(salt);
        // 注册
        Integer rows = userMapper.insert(user);
        if (rows != 1) {
            throw new UsernameDuplicatedException("在用户注册过程中发生了未知的异常");
        }
    }

    @Override
    public User login(String username, String password) { // 登录
        User result = userMapper.findByUsername(username);
        if (result == null) {
            throw new UserNotFoundException("用户数据不存在的异常");
        }
        if (result.getIsDelete() == 1) {
            throw new UserNotFoundException("用户数据不存在的错误");
        }
        // 获取盐值
        String salt = result.getSalt();
        String md5Pw = getMd5Pw(password, salt);
        if (!result.getPassword().equals(md5Pw)) {
            throw new PasswordNotMatchException("密码验证失败的错误");
        }
        result.setPassword("");
        return result;
    }

    @Override
    public void changePassword(String uid, String username, String oldPassword, String newPassword) { // 修改密码
        User result = userMapper.findByUid(uid);
        if (result == null) {
            throw new UserNotFoundException("用户数据不存在");
        }
        if (result.getIsDelete().equals(1)) {
            throw new UserNotFoundException("用户数据不存在");
        }
        String salt = result.getSalt();
        // 比较密码
        String oldMd5Pw = getMd5Pw(oldPassword, salt);
        if (!result.getPassword().contentEquals(oldMd5Pw)) {
            throw new PasswordNotMatchException("原密码错误");
        }
        // 新密码
        String newMd5Pw = getMd5Pw(newPassword, salt);
        Date now = new Date();
        Integer rows = userMapper.updatePasswordByUid(uid, newMd5Pw, username, now);
        if (rows != 1) {
            throw new UpdateException("更新用户数据时出现未知错误,请联系统管理员");
        }
    }

    @Override
    public User findByUid(String uid) { // 根据uid查询用户资料
        return userMapper.findByUid(uid);
    }


    
    private String getMd5Pw(String password, String salt) {
        for (int i = 0; i < 3; i++) {
            password = DigestUtils.md5DigestAsHex((salt + password).getBytes()).toUpperCase();
        }
        return password;
    }
}

10.在demo目录下新建controller目录,在controller目录下新建BaseController类用于返回异常结果
package com.example.demo.controll;

import com.example.demo.Service.ex.*;
import com.example.demo.util.JsonResult;
import org.springframework.web.bind.annotation.ExceptionHandler;


public class BaseController {
    // 成功状态码
    public static final int OK = 200;


    // 请求处理方法,这个方法的返回值就是需要传递给前端的数据
    @ExceptionHandler(ServiceException.class)  // 统一处理抛出的异常
    public JsonResult handlerException(Throwable e) {
        JsonResult result = new JsonResult<>(e);
        if(e instanceof UsernameDuplicatedException){
            result.setState(400);
            result.setMessage("用户名已经被占用");
        }else if(e instanceof UserNotFoundException){
            result.setState(500);
            result.setMessage("用户不存在");
        }else if(e instanceof PasswordNotMatchException){
            result.setState(600);
            result.setMessage("密码错误");
        }else if(e instanceof InsertException){
            result.setMessage("注册失败");
            result.setState(700);
        }else if(e instanceof UpdateException){
            result.setState(800);
            result.setMessage("修改密码失败");
        }
        return result;
    }
}

11.在controller目录下新建UserController类
package com.example.demo.controll;

import com.example.demo.Service.IUserService;
import com.example.demo.entity.User;
import com.example.demo.util.JWTUtils;
import com.example.demo.util.JsonResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;
import java.util.Map;

@RestController
@RequestMapping("users")
public class UserController extends BaseController {
    @Autowired
    private IUserService userService;

    // 用户注册
    @RequestMapping("/reg")
    public JsonResult reg(User user) {
        userService.reg(user);
        return new JsonResult<>(OK, "用户注册成功");
    }

    // 用户登录
    @RequestMapping("/login")
    public JsonResult login(String username, String password) {
        User user = userService.login(username, password);
        if (user != null) {
            Map map = new HashMap<>();
            map.put("username",user.getUsername());
            map.put("uid",user.getUid());
            String token = JWTUtils.getToken(map);
            user.setToken(token);
        }
        return new JsonResult<>(OK, "登录成功", user);
    }

    // 修改密码
    @RequestMapping("/change_password")
    public JsonResult changePassword(String uid, String username, String oldPassword, String newPassword) {
        userService.changePassword(uid, username, oldPassword, newPassword);
        return new JsonResult<>(OK, "修改成功");
    }

    // 获取用户信息
    @RequestMapping("/list")
    public JsonResult list(String uid) {
        User user = userService.findByUid(uid);
        return new JsonResult<>(OK,"获取成功",user);
    }

}

12.在demo下新建utils目录,在utils下新建JWTUtils类
package com.example.demo.util;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTCreator;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;

import java.util.Calendar;
import java.util.Map;

public class JWTUtils {


	// 秘钥
    private static final String  SING = "!Q@W3e4r%T^Y";

    
    public static String getToken(Map map){

        Calendar instance = Calendar.getInstance();
        instance.add(Calendar.DATE,7);//默认7天过期

        //创建jwt builder
        JWTCreator.Builder builder = JWT.create();

        // 将传进来的用户信息加入到token再生成
        map.forEach((k,v)->{
            builder.withClaim(k,v);
        });
        // 得到token
        String token = builder.withExpiresAt(instance.getTime())//指定令牌过期时间
                .sign(Algorithm.HMAC256(SING));// 机密方式为HMAC256,SING秘钥
        return token;
    }

    
    public static DecodedJWT verify(String token){
        return JWT.require(Algorithm.HMAC256(SING)).build().verify(token);
    }

}

13.在utils目录下新建JsonResult类用于封装返回结果集
package com.example.demo.util;

import java.io.Serializable;

public class JsonResult implements Serializable {
    // 状态码
    private Integer state;
    // 描述信息
    private String message;
    // 数据
    private E data;

    public JsonResult() {
    }

    public JsonResult(Integer state) {
        this.state = state;
    }

    public JsonResult(Throwable e) {
        this.message = e.getMessage();
    }

    public JsonResult(Integer state, E data) {
        this.state = state;
        this.data = data;
    }

    public Integer getState() {
        return state;
    }

    public void setState(Integer state) {
        this.state = state;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public E getData() {
        return data;
    }

    public void setData(E data) {
        this.data = data;
    }

    public JsonResult(Integer state, String message) {
        this.state = state;
        this.message = message;
    }

    public JsonResult(Integer state, String message, E data) {
        this.state = state;
        this.message = message;
        this.data = data;
    }
}

14.忘了还有两个实体类、在demo下创建entity目录,在entity下创建BaseEntity类
package com.example.demo.entity;

import java.io.Serializable;
import java.util.Date;
import java.util.Objects;

public class BaseEntity implements Serializable {
    private String createdUser;
    private Date createdTime;
    private String modifiedUser;
    private Date modifiedTime;

    public String getCreatedUser() {
        return createdUser;
    }

    public void setCreatedUser(String createdUser) {
        this.createdUser = createdUser;
    }

    public Date getCreatedTime() {
        return createdTime;
    }

    public void setCreatedTime(Date createdTime) {
        this.createdTime = createdTime;
    }

    public String getModifiedUser() {
        return modifiedUser;
    }

    public void setModifiedUser(String modifiedUser) {
        this.modifiedUser = modifiedUser;
    }

    public Date getModifiedTime() {
        return modifiedTime;
    }

    public void setModifiedTime(Date modifiedTime) {
        this.modifiedTime = modifiedTime;
    }

    @Override
    public String toString() {
        return "BaseEntity{" +
                "createdUser='" + createdUser + ''' +
                ", createdTime=" + createdTime +
                ", modifiedUser='" + modifiedUser + ''' +
                ", modifiedTime=" + modifiedTime +
                '}';
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof BaseEntity)) return false;
        BaseEntity that = (BaseEntity) o;
        return Objects.equals(getCreatedUser(), that.getCreatedUser()) &&
                Objects.equals(getCreatedTime(), that.getCreatedTime()) &&
                Objects.equals(getModifiedUser(), that.getModifiedUser()) &&
                Objects.equals(getModifiedTime(), that.getModifiedTime());
    }

    @Override
    public int hashCode() {
        return Objects.hash(getCreatedUser(), getCreatedTime(), getModifiedUser(), getModifiedTime());
    }
}

15.entity目录下继续新建User类
package com.example.demo.entity;

import java.util.Objects;

public class User extends BaseEntity {
    private String uid;
    private String username;
    private String password;
    private String salt;
    private String phone;
    private String email;
    private Integer gender;
    private String avatar;
    private Integer isDelete;

    public String getToken() {
        return token;
    }

    public void setToken(String token) {
        this.token = token;
    }

    private String token;

    public String getUid() {
        return uid;
    }

    public void setUid(String uid) {
        this.uid = uid;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getSalt() {
        return salt;
    }

    public void setSalt(String salt) {
        this.salt = salt;
    }

    public String getPhone() {
        return phone;
    }

    public void setPhone(String phone) {
        this.phone = phone;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public Integer getGender() {
        return gender;
    }

    public void setGender(Integer gender) {
        this.gender = gender;
    }

    public String getAvatar() {
        return avatar;
    }

    public void setAvatar(String avatar) {
        this.avatar = avatar;
    }

    public Integer getIsDelete() {
        return isDelete;
    }

    public void setIsDelete(Integer isDelete) {
        this.isDelete = isDelete;
    }

    @Override
    public String toString() {
        return "User{" +
                "uid='" + uid + ''' +
                ", username='" + username + ''' +
                ", password='" + password + ''' +
                ", salt='" + salt + ''' +
                ", phone='" + phone + ''' +
                ", email='" + email + ''' +
                ", gender=" + gender +
                ", avatar='" + avatar + ''' +
                ", isDelete=" + isDelete +
                ", token='" + token + ''' +
                '}';
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof User)) return false;
        if (!super.equals(o)) return false;
        User user = (User) o;
        return Objects.equals(getUid(), user.getUid()) &&
                Objects.equals(getUsername(), user.getUsername()) &&
                Objects.equals(getPassword(), user.getPassword()) &&
                Objects.equals(getSalt(), user.getSalt()) &&
                Objects.equals(getPhone(), user.getPhone()) &&
                Objects.equals(getEmail(), user.getEmail()) &&
                Objects.equals(getGender(), user.getGender()) &&
                Objects.equals(getAvatar(), user.getAvatar()) &&
                Objects.equals(getIsDelete(), user.getIsDelete()) &&
                Objects.equals(getToken(), user.getToken());
    }

    @Override
    public int hashCode() {
        return Objects.hash(super.hashCode(), getUid(), getUsername(), getPassword(), getSalt(), getPhone(), getEmail(), getGender(), getAvatar(), getIsDelete(), getToken());
    }
}

16.配置拦截规则、在demo下新建interceptor目录,在interceptor新建JWTinterceptor类
package com.example.demo.interceptor;

import com.auth0.jwt.exceptions.AlgorithmMismatchException;
import com.auth0.jwt.exceptions.SignatureVerificationException;
import com.auth0.jwt.exceptions.TokenExpiredException;
import com.example.demo.util.JWTUtils;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.Map;


public class JWTInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        Map map = new HashMap<>();
        //获取请求头中令牌
        String token = request.getHeader("token");
        try {
            JWTUtils.verify(token);//验证令牌
            return true;//放行请求
        } catch (SignatureVerificationException e) {
            e.printStackTrace();
            map.put("msg","无效签名!");
        }catch (TokenExpiredException e){
            e.printStackTrace();
            map.put("msg","token过期!");
        }catch (AlgorithmMismatchException e){
            e.printStackTrace();
            map.put("msg","token算法不一致!");
        }catch (Exception e){
            e.printStackTrace();
            map.put("msg","token无效!!");
        }
        map.put("state",false);//设置状态
        //将map 专为json  jackson
        String json = new ObjectMapper().writeValueAsString(map);
        response.setContentType("application/json;charset=UTF-8");
        response.getWriter().println(json);
        return false;
    }
}

17.在demo下新建config,在config目录下新建InterceptorConfig
package com.example.demo.config;

import com.example.demo.interceptor.JWTInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ConcurrentTaskExecutor;
import org.springframework.web.servlet.config.annotation.AsyncSupportConfigurer;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

@Configuration
public class InterceptorConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new JWTInterceptor())
                .addPathPatterns("/users/list")         //其他接口token验证
                .excludePathPatterns("/users/login");  //所有用户都放行
    }

    // 最大30线程,外加30列队;【拒绝策略AbortPolicy(默认):丢弃并抛出异常】
    private static ExecutorService executorService = new ThreadPoolExecutor(
            1, 30, 60L,
            TimeUnit.SECONDS, new ArrayBlockingQueue<>(3)
    );


    
    @Override
    public void configureAsyncSupport(AsyncSupportConfigurer configurer) {
        configurer.setTaskExecutor(new ConcurrentTaskExecutor(executorService));
        configurer.setDefaultTimeout(30000);
    }
}

18.运行app、获取users/list不带token 19.登录一下、返回token和用户信息

20.在访问users/list

Ok,到这里就结束了
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1031512.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号