依赖引入
使用开源技术包含:
Springboot
MybatisPlus:https://baomidou.com/
Knife4j:https://doc.xiaominfo.com/
Sa-token:https://sa-token.cc/doc.html
sa-token JWT 模式使用Token认证
核心配置依赖
<maven.compiler.source>21</maven.compiler.source>
<maven.compiler.target>21</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<hutool-all.version>5.8.36</hutool-all.version>
<sa.token.version>1.41.0</sa.token.version>
<commons.lang3.version>3.12.0</commons.lang3.version>
<lombok.version>1.18.36</lombok.version>
<spring-boot.version>3.4.4</spring-boot.version>
<mybatis-plus.version>3.5.10.1</mybatis-plus.version>
<mysql.version>8.0.33</mysql.version>
<knife4j.version>4.4.0</knife4j.version>
<mybatis-spring.version>3.0.3</mybatis-spring.version>
Pom依赖具体如下
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-parent</artifactId>
<version>3.4.4</version>
<relativePath/>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>com.gt.demo</groupId>
<artifactId>spring-satoken</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>21</maven.compiler.source>
<maven.compiler.target>21</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<hutool-all.version>5.8.36</hutool-all.version>
<sa.token.version>1.41.0</sa.token.version>
<commons.lang3.version>3.12.0</commons.lang3.version>
<lombok.version>1.18.36</lombok.version>
<spring-boot.version>3.4.4</spring-boot.version>
<mybatis-plus.version>3.5.10.1</mybatis-plus.version>
<mysql.version>8.0.33</mysql.version>
<knife4j.version>4.4.0</knife4j.version>
<mybatis-spring.version>3.0.3</mybatis-spring.version>
</properties>
<dependencies>
<!--Mysql数据库-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency>
<!--接口文档生成工具-->
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-openapi3-jakarta-spring-boot-starter</artifactId>
<version>${knife4j.version}</version>
</dependency>
<!--WEB容器集成排除默认使用自定义-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>${spring-boot.version}</version>
<!-- 排除默认的 Tomcat 依赖 -->
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<!--undertow web服务器-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-undertow</artifactId>
<version>${spring-boot.version}</version>
</dependency>
<!--mysql-orm框架-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>${mybatis-plus.version}</version>
<exclusions>
<exclusion>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
</exclusion>
</exclusions>
</dependency>
<!--解决mybatis-plus和spring兼容问题-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>${mybatis-spring.version}</version>
</dependency>
<!--mybatis-plus增强工具包分页插件--><!---->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-jsqlparser</artifactId>
<version>${mybatis-plus.version}</version>
</dependency>
<!--最强万能工具包Hu-tool工具包集成-->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>${hutool-all.version}</version>
</dependency>
<!--Sa-token认证授权框架-->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-spring-boot3-starter</artifactId>
<version>${sa.token.version}</version>
</dependency>
<!-- Sa-Token 整合 jwt -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-jwt</artifactId>
<version>${sa.token.version}</version>
</dependency>
<!-- lombok简化Bean -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
<optional>true</optional>
</dependency>
</dependencies>
<repositories>
<repository>
<id>snapshots</id>
<url>https://oss.sonatype.org/content/repositories/snapshots/</url>
</repository>
<repository>
<id>public</id>
<name>c nexus</name>
<url>https://maven.aliyun.com/repository/public/</url>
<releases>
<enabled>true</enabled>
</releases>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>public</id>
<name>aliyun nexus</name>
<url>https://maven.aliyun.com/repository/public/</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
</pluginRepository>
</pluginRepositories>
</project>
实现效果
未携带Token访问
先登录获取Token
携带获取Token访问开始的接口
项目整体介绍
核心代码实现
Sa-Token +JWT
核心就是集成依赖—>配置这个JWT的Bean
@Configuration
public class SaTokenConfig {
// Sa-Token 整合 jwt (Simple 简单模式)
@Bean
public StpLogic getStpLogicJwt() {
return new StpLogicJwtForSimple();
}
}
Sa-Token + Springboot-Web拦截请求,放行白名单接口
核心就是配置 WebMvcConfigurer 的资源过滤器
@Configuration
public class WebAppCoreConfig implements WebMvcConfigurer {
/**
* @return CorsConfiguration 跨域允许
* @author makeJava
* @since JDK 21 And SpringBoot 3.X
*/
private CorsConfiguration buildConfig() {
CorsConfiguration corsConfiguration = new CorsConfiguration();
// 1允许任何域名使用
corsConfiguration.addAllowedOrigin("*");
// 2允许任何头
corsConfiguration.addAllowedHeader("*");
// 3允许任何方法(post、get等)
corsConfiguration.addAllowedMethod("*");
return corsConfiguration;
}
@Bean
public ObjectMapper objectMapper(Jackson2ObjectMapperBuilder builder) {
// 禁用时间戳格式 支持 Java 8 时间类型
return builder
.featuresToDisable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
.modules(new JavaTimeModule())
.build();
}
/**
* @return CorsFilter 静态资源过滤
* @author makeJava
* @since JDK 21 And SpringBoot 3.X
*/
@Bean
public CorsFilter corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
// 4
source.registerCorsConfiguration("/**", buildConfig());
return new CorsFilter(source);
}
/**
* Description: 静态资源过滤
*
* @author makeJava
*/
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
//ClassPath:/Static/** 静态资源释放
registry.addResourceHandler("/**").addResourceLocations("classpath:/static/");
//释放swagger
registry.addResourceHandler("doc.html").addResourceLocations("classpath:/META-INF/resources/");
//释放webjars
registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
}
@Bean
public SaServletFilter getSaTokenFilter() {
return new SaServletFilter()
.addExclude("/static/**", "/css/**", "/js/**", "/images/**");
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 过滤掉不用鉴权的URl地址
List<String> patterns = new ArrayList<>();
patterns.add("/auth/doLogin");
patterns.add("/doc.html");
patterns.add("/favicon.ico");
patterns.add("/v3/**");
patterns.add("/webjars/**");
patterns.add("/login/**");
patterns.add("/static/**");
patterns.add("/svg/**");
patterns.add("/Vue/**");
patterns.add("/saToken/verify");
// 剩下的所有接口要鉴权访问
registry.addInterceptor(new SaInterceptor(handle -> StpUtil.checkLogin()))
.addPathPatterns("/**")
.excludePathPatterns(patterns);
WebMvcConfigurer.super.addInterceptors(registry);
}
}
Sa-Token 登录
@RequestMapping(value = "doLogin", method = RequestMethod.POST)
@Operation(summary = "会话登录接口")
public Resp<Object> doLogin(@RequestBody UserLoginRequest userLoginRequest) throws Exception {
// 获取前端提交的 账号名称 & 密码
boolean checkValue = StrUtil.hasBlank(userLoginRequest.getUsername(), userLoginRequest.getPassword());
if (checkValue) {
return Resp.error("用户名或密码不能为空");
}
// RSA 私钥解密
String aesBackPwd = RSAUtil.decryptByPrivateKey(RSAUtil.priKey, userLoginRequest.getPassword());
String password = SecureUtil.md5(aesBackPwd);
SysUser loginUser = sysUserService.todoCheckUserNameAndPassword(userLoginRequest.getUsername(), password);
// 第一步:比对前端提交的 账号名称 & 密码 是否正确,比对成功后开始登录
// 此处仅作模拟示例,真实项目需要从数据库中查询数据进行比对
if (loginUser != null) {
// 第二步:根据账号id,进行登录
// 此处填入的参数应该保持用户表唯一,比如用户id,不可以直接填入整个 User 对象
SaLoginParameter loginParameter = new SaLoginParameter();
loginParameter.setExtra("userId", loginUser.getUserId()).
setExtra("username", loginUser.getUserName()).
setExtra("deptId", loginUser.getDeptId()).
setExtra("phoneNumber", loginUser.getPhoneNumber()).
setExtra("nickName", loginUser.getNickName()).
setExtra("tenantId", loginUser.getTenantId());
StpUtil.login(loginUser.getUserId(), loginParameter);
StpUtil.getTokenSession().set("LOGIN_USER_KEY", loginUser);
// SaResult 是 Sa-Token 中对返回结果的简单封装,下面的示例将不再赘述
return Resp.ok("登录成功", StpUtil.getTokenValue());
}
return Resp.error("登录失败");
}
核心配置如下
spring:
jackson:
date-format: yyyy-MM-dd HH:mm:ss # 设置日期格式
time-zone: Asia/Shanghai # 设置时区
default-property-inclusion: non_null # 忽略 null 字段
serialization:
write-dates-as-timestamps: false # 禁用时间戳格式
deserialization:
fail-on-unknown-properties: false # 忽略未知字段
datasource:
username: admin
password: 123456
url: jdbc:mysql://localhost:3306/test_admin_123?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true
driver-class-name: com.mysql.cj.jdbc.Driver
type: com.zaxxer.hikari.HikariDataSource
hikari:
minimum-idle: 1
maximum-pool-size: 5
idle-timeout: 60000 # 1 min
max-lifetime: 180000 # 3 min
leak-detection-threshold: 120000 # 2 min
thymeleaf:
cache: false
mode: HTML
encoding: UTF-8
prefix: classpath:/templates/
suffix: .html
servlet:
content-type: text/html
mybatis-plus:
type-aliases-package: com.gt.demo.entity
mapper-locations: classpath*:/mapper/**/*.xml
configuration:
map-underscore-to-camel-case: true #开启驼峰命名
cache-enabled: false #开启二级缓存
log-impl: org.apache.ibatis.logging.slf4j.Slf4jImpl
check-config-location: true # 检查xml是否存在
global-config:
db-config:
logic-not-delete-value: 0
logic-delete-field: isDel
logic-delete-value: 2
sa-token:
# token 名称(同时也是 cookie 名称)
token-name: token
# token 有效期(单位:秒) 默认30天,-1 代表永久有效
timeout: 2592000
# token 最低活跃频率(单位:秒),如果 token 超过此时间没有访问系统就会被冻结,默认-1 代表不限制,永不冻结
active-timeout: -1
# 是否允许同一账号多地同时登录 (为 true 时允许一起登录, 为 false 时新登录挤掉旧登录)
is-concurrent: true
# 在多人登录同一账号时,是否共用一个 token (为 true 时所有登录共用一个 token, 为 false 时每次登录新建一个 token)
is-share: true
# token 风格(默认可取值:uuid、simple-uuid、random-32、random-64、random-128、tik)
token-style: uuid
# jwt秘钥
jwt-secret-key: 9f65af7dda3241a0adc93f9649
# 是否输出操作日志
is-log: false
# 允许动态设置 token 有效期
dynamic-active-timeout: true
# 允许从 请求参数 读取 token
is-read-body: true
# 允许从 header 读取 token
is-read-header: true
# 关闭 cookie 鉴权 从根源杜绝 csrf 漏洞风险
is-read-cookie: false
# springdoc-openapi项目配置
springdoc:
swagger-ui:
path: /swagger-ui.html
tags-sorter: alpha
operations-sorter: alpha
url: /v3/api-docs
api-docs:
path: /v3/api-docs
group-configs:
- group: 'default'
paths-to-match: '/**'
packages-to-scan: com.gt.demo.controller
# knife4j的增强配置,不需要增强可以不配
knife4j:
# 开启增强配置
enable: true
# 开启Swagger的Basic认证功能,默认是false
basic:
enable: false
username: admin
password: admin123
setting:
language: zh_cn
然后非白名单接口访问系统就需要携带Header里面的Token了
Springboot的系统登录访问就搞定了。。。
更多Sa-Token用法参考官网,,真的很详细
链接–>https://sa-token.cc/doc.html#/
想要项目demo吗!!!!!
源码地址:
https://download.csdn.net/download/user_admin_god/90521960
数据库测试:
/*
Navicat Premium Data Transfer
Source Server : 本地Mysql8
Source Server Type : MySQL
Source Server Version : 80040 (8.0.40)
Source Host : localhost:3306
Source Schema : test_admin_123
Target Server Type : MySQL
Target Server Version : 80040 (8.0.40)
File Encoding : 65001
Date: 22/04/2025 17:11:25
*/
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for sys_user
-- ----------------------------
DROP TABLE IF EXISTS `sys_user`;
CREATE TABLE `sys_user` (
`user_id` bigint NOT NULL COMMENT '用户ID',
`tenant_id` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '000000' COMMENT '租户编号',
`dept_id` bigint NULL DEFAULT NULL COMMENT '部门ID',
`user_name` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '用户账号',
`nick_name` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '用户昵称',
`user_type` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT 'sys_user' COMMENT '用户类型(sys_user系统用户)',
`email` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '用户邮箱',
`phone_number` varchar(11) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '手机号码',
`sex` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '0' COMMENT '用户性别(0男 1女 2未知)',
`avatar` bigint NULL DEFAULT NULL COMMENT '头像地址',
`password` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '密码',
`status` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '0' COMMENT '帐号状态(0正常 1停用)',
`del_flag` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '0' COMMENT '删除标志(0代表存在 2代表删除)',
`login_ip` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '最后登录IP',
`login_date` datetime NULL DEFAULT NULL COMMENT '最后登录时间',
`create_dept` bigint NULL DEFAULT NULL COMMENT '创建部门',
`create_by` bigint NULL DEFAULT NULL COMMENT '创建者',
`create_time` datetime NULL DEFAULT NULL COMMENT '创建时间',
`update_by` bigint NULL DEFAULT NULL COMMENT '更新者',
`update_time` datetime NULL DEFAULT NULL COMMENT '更新时间',
`remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备注',
PRIMARY KEY (`user_id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '用户信息表' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of sys_user
-- ----------------------------
INSERT INTO `sys_user` VALUES (1, '000000', 103, 'admin', '白嫖老郭', 'sys_user', 'crazyLionLi@163.com', '15888888888', '1', NULL, '21232f297a57a5a743894a0e4a801fc3', '1', '0', '0:0:0:0:0:0:0:1', '2024-11-26 15:20:32', 103, 1, '2024-11-12 19:33:19', 1, '2024-11-26 15:20:32', '管理员');
INSERT INTO `sys_user` VALUES (3, '000000', 108, 'test', '本部门及以下 密码666666', 'sys_user', '', '', '0', NULL, 'f379eaf3c831b04de153469d1bec345e', '0', '0', '127.0.0.1', '2024-11-12 19:33:19', 103, 1, '2024-11-12 19:33:19', 3, '2024-11-12 19:33:19', NULL);
INSERT INTO `sys_user` VALUES (4, '000000', 102, 'test1', '仅本人 密码666666', 'sys_user', '', '', '0', NULL, 'f379eaf3c831b04de153469d1bec345e', '0', '0', '127.0.0.1', '2024-11-12 19:33:19', 103, 1, '2024-11-12 19:33:19', 4, '2024-11-12 19:33:19', NULL);
INSERT INTO `sys_user` VALUES (1866004939061002241, '000000', 103, 'super', '超级管理员', 'sys_user', '1054765292@qq.com', '1862289322', '0', 10, 'e10adc3949ba59abbe56e057f20f883e', '1', '0', '0:0:0:0:0:0:0:1', NULL, 103, 1, '2024-12-09 14:20:21', 1, '2025-01-19 13:20:07', '密码123456');
INSERT INTO `sys_user` VALUES (1880823650330529794, '000000', 103, '我是你', '我是你', 'sys_user', '22432@aa.com', '13423232323', '1', 10084, '23467bb4f4fd36f799477ce8d5f0203e', '1', '2', '0:0:0:0:0:0:0:1', NULL, 103, 1, '2025-01-19 11:44:37', 1, '2025-01-19 13:34:35', '符合哦热偶');
INSERT INTO `sys_user` VALUES (1880851510122409986, '000000', 108, 'xiaolaodi', '小老弟', 'sys_user', '2222@qq.com', '13722628322', '1', 10084, '15a8782405f28269c2d5c417202bfd0e', '1', '0', '0:0:0:0:0:0:0:1', NULL, 103, 1, '2025-01-19 13:35:19', 1, '2025-01-19 13:35:19', '请叫我小老弟');
INSERT INTO `sys_user` VALUES (1914582909136343042, '000000', 103, 'woshidageda', '我是大哥大', 'sys_user', 'dwedef@qq.com', '13677628322', '0', 10084, '25d55ad283aa400af464c76d713c07ad', '1', '0', '0:0:0:0:0:0:0:1', NULL, 103, 1, '2025-04-22 15:31:51', 1, '2025-04-22 15:31:51', '我是大哥大');
SET FOREIGN_KEY_CHECKS = 1;