sa-token前后端分离集成redis与jwt基础案例

目录

前言

sa-token官方文档:https://sa-token.cc
Sa-Token 是一个轻量级 Java 权限认证框架,主要解决:登录认证权限认证单点登录OAuth2.0分布式Session会话微服务网关鉴权 等一系列权限相关问题。

本教程的环境是springboot 2.6,jdk1.8

1,依赖引入

sa-token依赖:

xml 复制代码
        <dependency>
            <groupId>cn.dev33</groupId>
            <artifactId>sa-token-spring-boot-starter</artifactId>
            <version>1.39.0</version>
        </dependency>

sa-token集成jwt:

xml 复制代码
        <dependency>
            <groupId>cn.dev33</groupId>
            <artifactId>sa-token-jwt</artifactId>
            <version>1.39.0</version>
        </dependency>

sa-token集成redis

xml 复制代码
        <dependency>
            <groupId>cn.dev33</groupId>
            <artifactId>sa-token-redis-jackson</artifactId>
            <version>1.39.0</version>
        </dependency>

这里我用的是security带的BCrypt密码加密,所以还导入了:

xml 复制代码
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-crypto</artifactId>
        </dependency>

2,相关配置

springboot配置文件

需要注意集成redis后,要想redis起作用还需要将 is-read-cookie 设为 false

配置jwt密钥 jwt-secret-key 随便打个长的字符就行了

数据库和redis连接请自行设置

yaml 复制代码
# sa-token 配置
sa-token:
  # token 名称(同时也是 cookie 名称)
  token-name: Authorization
  # token 有效期(单位:秒) 默认30天,-1 代表永久有效
  timeout: 86400
  # token 最低活跃频率(单位:秒),如果 token 超过此时间没有访问系统就会被冻结,默认-1 代表不限制,永不冻结
  active-timeout: -1
  # 是否允许同一账号多地同时登录 (为 true 时允许一起登录, 为 false 时新登录挤掉旧登录)
  is-concurrent: false
  # 在多人登录同一账号时,是否共用一个 token (为 true 时所有登录共用一个 token, 为 false 时每次登录新建一个 token)
  is-share: false
  # token 风格(默认可取值:uuid、simple-uuid、random-32、random-64、random-128、tik)
  token-style: uuid
  #  配置jwt密钥
  jwt-secret-key: sadfsadfasdfsdafasfdseafasfdsadfsadfsa
  # token前缀
  token-prefix: Bearer
  # 是否输出操作日志
  is-log: true
  # 是否尝试从 cookie 里读取 Token,此值为 false 后,StpUtil.login(id) 登录时也不会再往前端注入Cookie
  #  注意:当使用 redis 作为缓存数据时要将 此关闭,否则不会将redis作为缓存,而是继续使用cookie
  is-read-cookie: false

配置类:

redis序列化:
java 复制代码
package com.satokendemo.config;

import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;

@Configuration
public class RedisConfig extends CachingConfigurerSupport {
    @Bean
    public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
        RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(new StringRedisSerializer());
        redisTemplate.setHashValueSerializer(new StringRedisSerializer());
        redisTemplate.setConnectionFactory(connectionFactory);
        return redisTemplate;
    }
}
配置集成jwt和加密的实例:
java 复制代码
package com.satokendemo.config;

import cn.dev33.satoken.jwt.StpLogicJwtForSimple;
import cn.dev33.satoken.stp.StpLogic;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
 
@Configuration
public class SaTokenConfig {

    /**
     * 配置集成jwt
     * @return StpLogic
     */
    @Bean
    public StpLogic getStpLogicJwt() {
        return new StpLogicJwtForSimple();
    }

    /**
     * 密码加密配置
     * @return BCryptPasswordEncoder
     */
    @Bean
    public BCryptPasswordEncoder bCryptPasswordEncoder(){
        return new BCryptPasswordEncoder();
    }

}
配置拦截器,进行身份和权限校验:

该配置的作用是不拦截登录,注册和一些文档接口,即匿名访问。

其它的接口都拦截,并进行是否登录的校验,未登录的用户将无法访问。

java 复制代码
package com.satokendemo.config;

import cn.dev33.satoken.fun.SaParamFunction;
import cn.dev33.satoken.interceptor.SaInterceptor;
import cn.dev33.satoken.stp.StpUtil;
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 WebMVCConfig implements WebMvcConfigurer {

    /**
     * 配置saToken的身份权限拦截器
     *
     * @param registry
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new SaInterceptor(new SaParamFunction<Object>() {
                    // 是否登录
                    @Override
                    public void run(Object o) {
                        // 调用sa-token提供的方法,校验用户身份登录
                  // 该操作的官网文档地址:https://sa-token.cc/doc.html#/use/route-check
                        StpUtil.checkLogin();
                    }
                }))
                // 将所有路径都拦截
                .addPathPatterns("/**")
                // 排除不拦截的路径
                .excludePathPatterns(
                        "/sysUser/login",
                        "/sysUser/register",
                        "/doc.html",
                        "/webjars/**",
                        "/swagger-resources"
                );
    }
}

3,登录与退出

代码:

StpUtil.login(): sa-token的登录方法,里面填入用户唯一标识,一般为用户id。因为集成了redis所以登录时会将会话信息存入redis中。同时生成token。token过期后redis中的数据也会被删除

StpUtil.getTokenValue():获取token的方法,登录之后调用,返回token,因为已经集成了jwt,所以返回的是 jwt token。

StpUtil.logout():退出登录的方法,调用后token将失效,且redis存储的信息也将被删除

获取登录用户的id方法:

java 复制代码
package com.satokendemo.controller;

import cn.dev33.satoken.stp.StpUtil;
import com.satokendemo.result.Result;
import lombok.RequiredArgsConstructor;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.web.bind.annotation.*;

import java.util.Map;

@RestController
@RequiredArgsConstructor
@RequestMapping("sysUser")
public class SysUserController {

    private final BCryptPasswordEncoder bCryptPasswordEncoder;
    
    // 登录接口
    @PostMapping("/login")
    public Result<String> login(@RequestBody Map<String,String> sysUser) {

         if (!sysUser.containsKey("username") || !sysUser.containsKey("password")){
             return Result.error(401,"用户名或密码为空");
         }
        String username = "admin";
        // 使用 BCrypt 加密后的 123456
        String password = "$2a$10$QIVz.q.uRrqYiiKzK60jGetU/mRWrgPzVoxesgUen3tDVXsfmKB0K";
        if (sysUser.get("username").equals("admin")&& bCryptPasswordEncoder.matches(sysUser.get("password"),"$2a$10$QIVz.q.uRrqYiiKzK60jGetU/mRWrgPzVoxesgUen3tDVXsfmKB0K")){
            StpUtil.login(1000); // 这里输入用户id
            return Result.success(StpUtil.getTokenValue());
        }
        return Result.error(401,"用户名或密码错误");
    }
    
    // 退出登录接口
    @PostMapping("/logout")
    public Result<String> logout() {
        // 调用sa-token的退出登录方法
        StpUtil.logout();
        return Result.success("退出成功");
    }

}
相关推荐
江小北2 小时前
美团面试:MySQL为什么能够在大数据量、高并发的业务中稳定运行?
后端
zhaomy20252 小时前
从ThreadLocal到ScopedValue:Java上下文管理的架构演进与实战指南
java·后端
华仔啊2 小时前
10分钟搞定!SpringBoot+Vue3 整合 SSE 实现实时消息推送
java·vue.js·后端
稚辉君.MCA_P8_Java2 小时前
Gemini永久会员 Go 实现动态规划
数据结构·后端·算法·golang·动态规划
SimonKing3 小时前
你的IDEA还缺什么?我离不开的这两款效率插件推荐
java·后端·程序员
武子康3 小时前
大数据-165 Apache Kylin Cube7 实战:聚合组/RowKey/编码与体积精度对比
大数据·后端·apache kylin
qinyia3 小时前
WisdomSSH解决因未使用Docker资源导致的磁盘空间不足问题
运维·服务器·人工智能·后端·docker·ssh·github
庄宿正3 小时前
【Vue2+SpringBoot+SM2】Vue2 + Spring Boot 实现 SM2 双向非对称加密完整实战
java·spring boot·后端