SpringBoot 3 集成 Sa-Token 实现权限相关功能

1、Sa-Token 介绍

1.1 Sa-Token 开发文档:https://sa-token.cc

1.2 Sa-Token 是一个轻量级 Java 权限认证框架,主要解决:登录认证权限认证单点登录OAuth2.0微服务鉴权 等一系列权限相关问题。

1.3 功能结构图

2、 SpringBoot 3 集成 Sa-Token

2.1 Maven

<!-- Sa-Token -->
<dependency>
    <groupId>cn.dev33</groupId>
    <artifactId>sa-token-spring-boot3-starter</artifactId>
    <version>1.38.0</version>
</dependency>

<!-- Sa-Token 集成 jwt -->
<dependency>
    <groupId>cn.dev33</groupId>
    <artifactId>sa-token-jwt</artifactId>
    <version>1.38.0</version>
</dependency>

<!-- Sa-Token 集成 redis, 并使用 jackson 序列化 -->
<dependency>
    <groupId>cn.dev33</groupId>
    <artifactId>sa-token-redis-jackson</artifactId>
    <version>1.38.0</version>
</dependency>

<!-- 提供Redis连接池 -->
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-pool2</artifactId>
</dependency>

<!-- fastjson2 处理 json 数据 -->
<dependency>
    <groupId>com.alibaba.fastjson2</groupId>
    <artifactId>fastjson2</artifactId>
    <version>2.0.48</version>
</dependency>

<!-- 使用 springdoc 生成 swagger 文档  -->
<dependency>
    <groupId>org.springdoc</groupId>
    <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
    <version>2.5.0</version>
</dependency>

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
    <groupId>com.mysql</groupId>
    <artifactId>mysql-connector-j</artifactId>
    <version>8.3.0</version>
</dependency>

<!-- mybatis-plus-boot-starter 中 mybatis-spring 版本不够,排除之后引入新版本 -->
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.5.6</version>
    <exclusions>
        <exclusion>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
        </exclusion>
    </exclusions>
</dependency>

<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis-spring</artifactId>
    <version>3.0.3</version>
</dependency>

2.2 yml 配置 sa-token

server:
  port: 8080

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/xxx
    username: xxx
    password: xxx
  data:
    redis:
      database: 1

sa-token:
  token-name: X-Token
  # token有效期,单位s 默认30天, -1代表永不过期
  timeout: -1
  # token 最低活跃频率(单位:秒),如果 token 超过此时间没有访问系统就会被冻结,默认-1 代表不限制,永不冻结
  active-timeout: 3600
  # jwt秘钥
  jwt-secret-key: qazwsxedc

# 文件上传下载目录
files:
  upload:
    path: D:/files/

2.3 常量

package com.dragon.springboot3vue3.common;

import io.swagger.v3.oas.annotations.media.Schema;

@Schema(description = "常量")
public class Constant {

    // SaResult 默认设置了 200 为成功, 500 为 失败
    
    /********** CODE & MSG **********/
    public static final String TOKEN= "X-Token";
    public static final String USER_PASSWORD= "123456";
    public static final int TOKEN_INVALID_CODE = 20001; public static final String TOKEN_INVALID_MSG = "Token无效,请重新登录";
    public static final int USERNAME_OCCUPIED_CODE = 20002; public static final String USERNAME_OCCUPIED_MSG = "用户名被占用,请重新输入";
    public static final int USERNAME_OR_PASSWORD_ERROR_CODE = 20003; public static final String USERNAME_OR_PASSWORD_ERROR_MSG = "用户名或密码输入错误";
    public static final int MISSING_NECESSARY_PARAMETERS_CODE = 20004; public static final String MISSING_NECESSARY_PARAMETERS_MSG = "缺少必要的参数";
    public static final int ORIGINAL_PASSWORD_ERROR_CODE = 20005; public static final String ORIGINAL_PASSWORD_ERROR_MSG = "原密码输入错误";
    public static final int PASSWORD_INCONSISTENCY_CODE = 20006; public static final String PASSWORD_INCONSISTENCY_MSG = "两次输入的新密码不一致";

    //  请求白名单,请求会放行
    public static final String[] WHITE_LIST = {
            "/user/register",
            "/user/login",
            "/user/logout",
            "/swagger-ui/**",
            "/v3/**",
            "/files/{fileName}",
    };
}

2.4 config-配置类

2.4.1 跨域配置类

package com.dragon.springboot3vue3.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
import java.util.List;

/**
 * 跨域配置类
 */
@Configuration
public class CorsConfig {

    @Bean
    public CorsFilter corsFilter(){
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        corsConfiguration.setAllowedOrigins(List.of("http://localhost:3000", "http://127.0.0.1:5173","http://localhost:5173")); // 设置允许的来源
        corsConfiguration.setAllowedMethods(List.of("*"));     // 设置允许的方法
        corsConfiguration.setAllowedHeaders(List.of("*"));     // 设置允许的头部
        corsConfiguration.setAllowCredentials(true); // 允许携带凭证

        UrlBasedCorsConfigurationSource urlBasedCorsConfigurationSource = new UrlBasedCorsConfigurationSource();
        urlBasedCorsConfigurationSource.registerCorsConfiguration("/**",corsConfiguration);

        return new CorsFilter(urlBasedCorsConfigurationSource);
    }
}

2.4.2 SaToken 配置类

package com.dragon.springboot3vue3.config;

import cn.dev33.satoken.interceptor.SaInterceptor;
import cn.dev33.satoken.jwt.StpLogicJwtForSimple;
import cn.dev33.satoken.router.SaRouter;
import cn.dev33.satoken.stp.StpLogic;
import cn.dev33.satoken.stp.StpUtil;
import com.dragon.springboot3vue3.common.Constant;
import org.springframework.context.annotation.Bean;
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 SaTokenConfigure implements WebMvcConfigurer {
    // Sa-Token 整合 jwt (Simple 简单模式)
    @Bean
    public StpLogic getStpLogicJwt() {
        return new StpLogicJwtForSimple();
    }

    // 注册 Sa-Token 拦截器
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new SaInterceptor(handle -> {
            // 登录拦截,放行白名单
            SaRouter.match("/**").notMatch(Constant.WHITE_LIST).check(r -> StpUtil.checkLogin());

        }))
        .addPathPatterns("/**");
    }
}

2.4.3 Swagger 配置类

package com.dragon.springboot3vue3.config;

import io.swagger.v3.oas.models.ExternalDocumentation;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.info.License;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class SwaggerConfig {

    @Bean
    public OpenAPI openAPI() {
        OpenAPI openAPI = new OpenAPI();
        openAPI.info(new Info().title("前后端分离管理系统")
                               .description("使用springboot3-vue3等技术")
                               .version("v1.0.0")
                               .license(new License().name("Apache 2.0").url("https://springdoc.org")));
        openAPI.externalDocs(new ExternalDocumentation().description("项目API文档")
                                                        .url("/"));
        return openAPI;
    }
}

2.4.4 MybatisPlus 配置类

package com.dragon.springboot3vue3.config;

import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MybatisPlusConfig {
    /**
     * 添加 MybatisPlus 分页插件
     */
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        return interceptor;
    }
}

2.5 实现登录认证

2.5.1 SaResult - SaToken封装的结果集

2.5.2 StpUtil - SaToken的鉴权工具类Sa-Token

2.5.3 StringRedisTemplate  - Redis工具类

2.5.4 BCrypt - 密码加密方式Sa-Token

2.5.5 @Tag、@OperationSwagger(SpringDoc)注解

package com.dragon.springboot3vue3.controller;

import cn.dev33.satoken.secure.BCrypt;
import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.util.SaResult;
import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.dragon.springboot3vue3.common.Constant;
import com.dragon.springboot3vue3.controller.dto.entityDto.RegisterOrLoginDto;
import com.dragon.springboot3vue3.controller.dto.entityDto.UserDto;
import com.dragon.springboot3vue3.controller.dto.pageDto.UserPageDto;
import com.dragon.springboot3vue3.entity.User;
import com.dragon.springboot3vue3.service.IUserService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Tag(name = "用户接口")
@RestController
@RequestMapping("/user")
public class UserController {
    @Autowired
    private IUserService userService;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Operation(summary = "注册")
    @PostMapping("/register")
    public SaResult register(@RequestBody @Validated RegisterOrLoginDto registerDto){
        User user=userService.lambdaQuery().eq(User::getUsername,registerDto.getUsername()).one();
        if(user!=null){
            return SaResult.error(Constant.USERNAME_OCCUPIED_MSG).setCode(Constant.USERNAME_OCCUPIED_CODE);
        }
        user=new User();
        BeanUtils.copyProperties(registerDto,user);
        // BCrypt.hashpw() 密码加密
        user.setPassword(BCrypt.hashpw(registerDto.getPassword(), BCrypt.gensalt()));
        userService.save(user);
        return SaResult.ok();
    }

    @Operation(summary = "登录")
    @PostMapping("/login")
    public SaResult login(@RequestBody @Validated RegisterOrLoginDto loginDto){
        User user=userService.lambdaQuery().eq(User::getUsername,loginDto.getUsername()).one();
        // BCrypt.checkpw(前端明文,后端密文)
        if(user!=null && BCrypt.checkpw(loginDto.getPassword(),user.getPassword())){
            // 登录认证
            StpUtil.login(user.getId());
            // 生成token,token 信息自动存入redis,在yml里配置 sa-token 相关信息
            String token = StpUtil.getTokenValue();
            // 将用户信息存入 redis
            stringRedisTemplate.opsForValue().set(user.getId(), JSON.toJSONString(user),1, TimeUnit.DAYS);

            return SaResult.ok().setData(token);
        }
        return SaResult.error(Constant.USERNAME_OR_PASSWORD_ERROR_MSG).setCode(Constant.USERNAME_OR_PASSWORD_ERROR_CODE);
    }

    @Operation(summary = "注销")
    @PostMapping("/logout")
    public SaResult logout(){
        StpUtil.logout();
        return SaResult.ok();
    }

    @Operation(summary = "获取登录用户信息")
    @GetMapping("/userInfo")
    public SaResult userInfo(){
        // Redis 中获取登录的用户信息
        String userInfo = stringRedisTemplate.opsForValue().get(StpUtil.getLoginIdAsString());
        User user= JSON.parseObject(userInfo,User.class);
        return SaResult.ok().setData(user);
    }
}

2.6 swagger-ui地址:http://localhost:8080/swagger-ui/index.html

SpringBoot中整合sa-token,可以按照以下步骤进行操作。 1. 添加依赖:在`pom.xml`文件中添加sa-token的Redis集成包依赖。可以使用官方提供的Redis集成包`sa-token-dao-redis-jackson`,具体依赖如下: ``` <dependency> <groupId>cn.dev33</groupId> <artifactId>sa-token-dao-redis-jackson</artifactId> <version>1.34.0</version> </dependency> ``` 2. 配置sa-token:在SpringBoot的配置文件中,配置sa-token相关属性,包括Redis连接信息、token有效期等。可以参考sa-token的官方文档进行配置。 3. 注解鉴权:在需要进行鉴权的方法上添加相应的注解。例如,使用`@SaCheckLogin`注解表示该方法需要登录认证,使用`@SaCheckRole`注解表示该方法需要具有指定角色才能访问。可以根据具体需求选择合适的注解进行鉴权。 4. 注册拦截器:在高版本的SpringBoot中(≥2.6.x),需要额外添加`@EnableWebMvc`注解才能使注册拦截器生效。可以在配置类上添加该注解。 通过以上步骤,就可以在SpringBoot中成功整合sa-token,并实现基于注解的鉴权功能。请根据具体需求进行配置和使用。 #### 引用[.reference_title] - *1* [【SaToken使用】SpringBoot整合SaToken(一)token自动续期+token定期刷新+注解鉴权](https://blog.csdn.net/weixin_43165220/article/details/126889045)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [springboot:整合sa-token](https://blog.csdn.net/weixin_43296313/article/details/124274443)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [Spring Boot中使用Sa-Token实现轻量级登录与鉴权](https://blog.csdn.net/m0_71777195/article/details/129175616)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值