当前位置: 首页 > news >正文

对接SaToken @SaCheckEL 鉴权注解

对接SaToken @SaCheckEL 鉴权注解

文章目录

  • 对接SaToken @SaCheckEL 鉴权注解
  • 前言
  • 一、引入插件和配置SaToken属性配置
  • 二、配置
    • 1.自定义SaTokenInterceptor并注入Bean
    • 2.WebMvcConfig配置SaTokenInterceptor,拦截所有请求路径
  • 三、重载SaToken权限接口和方法注入@SaCheckEL
    • 1.重载SaToken权限接口
    • 2.控制层注入@SaCheckEL


前言

原生SpringBoot 2.6.3、Spring 5.3.25(JDK8) 框架系统 对接SaToken 身份认证,使用 SpEL 表达式进行资源请求的鉴权。

一、引入插件和配置SaToken属性配置

        <!-- Sa-Token 权限认证,用于启动SaTokenContext实现 -->
        <dependency>
            <groupId>cn.dev33</groupId>
            <artifactId>sa-token-spring-boot-starter</artifactId>
            <version>1.40.0</version>
        </dependency>
        <!-- Sa-Token 注解鉴权使用 EL 表达式 -->
        <dependency>
            <groupId>cn.dev33</groupId>
            <artifactId>sa-token-spring-el</artifactId>
            <version>1.40.0</version>
        </dependency>
sa-token:
  # token前缀
  token-prefix: Bearer
  # token名称 (同时也是cookie名称)
  token-name: Token
  # token有效期,单位s 默认12小时, -1代表永不过期
  timeout: 43200
  # token临时有效期 (指定时间内无操作就视为token过期) 单位: 秒
  active-timeout: -1
  # 是否允许同一账号并发登录 (为true时允许一起登录, 为false时新登录挤掉旧登录)
  is-concurrent: true
  # 在多人登录同一账号时,是否共用一个token (为true时所有登录共用一个token, 为false时每次登录新建一个token)
  is-share: false
  # token风格
  token-style: uuid
  # 是否输出操作日志
  is-log: false

二、配置

1.自定义SaTokenInterceptor并注入Bean

SaTokenInterceptor类

@Component
@Slf4j
public class SaTokenInterceptor implements HandlerInterceptor {
	@Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws IOException {
        log.debug("------------>进入拦截器SaTokenInterceptor:{}", handler.toString());
        response.setHeader("Access-Control-Allow-Origin", "*");
        response.setHeader("Access-Control-Allow-Credentials", "true");
        response.setHeader("Access-Control-Allow-Methods", "GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS");
        response.setHeader("Access-Control-Max-Age", "86400");
        response.setHeader("Access-Control-Allow-Headers", "*");
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json;charset=UTF-8");
        //当请求路径包含/doc.html(swagger文档),跳过Token验证
        if ( swaggerDocSkipToken(request.getRequestURI())) {
            return true;
        }
        String token = request.getHeader("satoken");
        String baseToken = request.getHeader("token");
        SaSession tokenSession = null;

        if (StrUtil.isEmpty(baseToken) || StrUtil.isEmpty(token)) {
            PrintWriter out = response.getWriter();
            QuantdoResponse resp = new QuantdoResponse();
            log.info("SaTokenInterceptor:Satoken=" + token + ",Token=" + baseToken + "为空!");
            resp.setCode(OrderNotLoginException.TOKEN_TIMEOUT_CODE);
            resp.setMessage(OrderNotLoginException.TOKEN_TIMEOUT_MESSAGE);
            out.append(JSONObject.toJSONString(resp));
            return false;
        }

        if (StrUtil.isNotBlank(token)) {
            tokenSession = StpUtil.getTokenSessionByToken(token);
        }

        if (tokenSession != null ) {
            Long userId = (Long) tokenSession.getLoginId(); 
            return true;
        } else {
                PrintWriter out = response.getWriter();
                QuantdoResponse resp = new QuantdoResponse();
                log.info("SaTokenInterceptor:未获取到登录用户信息!");               resp.setCode(OrderNotLoginException.NOT_VALID_EMP_CODE);
                return false;
            }
        }
        else{
            PrintWriter out = response.getWriter();
            QuantdoResponse resp = new QuantdoResponse();
            log.info("SaTokenInterceptor:未获取到令牌satoken!");
            resp.setCode(OrderNotLoginException.TOKEN_TIMEOUT_CODE);
            out.append(JSONObject.toJSONString(resp));
            return false;
        }
    }

    //Swagger Doc
    public static final boolean swaggerDocSkipToken(String requestURL){
        if (requestURL.contains("/doc.html") || requestURL.contains(".js") || requestURL.contains(".css")
         || requestURL.contains(".ico") || requestURL.contains("/swagger-resources")
         || requestURL.contains("/api-docs")  ) {
            return true;
        }
        else{
            return false;
        }
    }
}

SaTokenConfig 类注入SaTokenInterceptor Bean

package com.isoftstone.order.service.config;
import com.isoftstone.order.service.interceptor.SaTokenInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class SaTokenConfig {
    @Bean
    public SaTokenInterceptor getSaTokenInterceptor() {
        return new SaTokenInterceptor();
    }
}

2.WebMvcConfig配置SaTokenInterceptor,拦截所有请求路径

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
    @Autowired
    private SaTokenInterceptor saTokenInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(saTokenInterceptor)
                .addPathPatterns("/**") // 拦截所有请求路径
                .excludePathPatterns("/login", "/assets/**"); 
                // 排除登录和注册接口
    }

    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
        ObjectMapper objectMapper = new ObjectMapper();
        SimpleModule module = new SimpleModule();
        module.addSerializer(Long.class, ToStringSerializer.instance);
        module.addSerializer(Long.TYPE, ToStringSerializer.instance);
        objectMapper.registerModule(module);
        objectMapper.configure(
        DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES,false);
        converter.setObjectMapper(objectMapper);
        converters.add(0,converter);
    }
}

三、重载SaToken权限接口和方法注入@SaCheckEL

1.重载SaToken权限接口

/**
 * @Description 工单权限校验,完成 Sa-Token 的自定义权限验证扩展
 * @Date 2025/2/18 16:11
 * @Created by chenjun
 */
@Component
@Slf4j
public class OrderStpInterfaceImpl implements StpInterface {
    @Autowired
    private UserAndRoleService userAndRoleService;
    @Resource
    private StringRedisUtil stringRedisUtil;
    public static final String env = "test";//'local'环境跳过Permission认证
    /**
     * 通过用户id查询用户基础资源表code集合,单个资源表code如:tenant:tenant:user:add
     * @param loginId  账号id:登录defUser实体id
     * @param loginType 账号类型
     * @return "tenant:tenant:user|tenant:tenant:user:query|tenant:tenant:user:add|tenant:tenant:user:delete|tenant:tenant:user:edit";
     *
     */
    @Override
    public List<String> getPermissionList(Object loginId, String loginType) {
        List<String> resourceCodes = userAndRoleService.getMenuResourceCodeByUser(loginId);
        return resourceCodes;
    }

    @Override
    public List<String> getRoleList(Object loginId, String loginType) {
        return null;
    }
}

2.控制层注入@SaCheckEL

用户控制层UserRest 注入@SaCheckEL

@Api(tags = {"用户控制层"})
@RestController
@RequestMapping("/userRest/")
public class UserRest {

    @Autowired
    private UserService userService;

    //用户查询
    @SaCheckEL("stp.checkPermission('tenant:tenant:user:query')")
    @GetMapping("")
    public List<OrderWorkListResp> query(){
        .....
    }

    //用户增加
    @SaCheckEL("stp.checkPermission('tenant:tenant:user:add')")
    @PostMapping("")
    public boolean add(User vo){
        .....
    }

    //用户编辑
    @SaCheckEL("stp.checkPermission('tenant:tenant:user:edit')")
    @PutMapping("")
    public boolean edit(User vo){
        .....
    }
}

注明:
多个权限注入方法@SaCheckEL(“stp.checkPermissionOr(‘tenant:tenant:user:query’,‘tenant:tenant:user:add’)”)

@SaCheckEL(“stp.checkPermissionAnd(‘tenant:tenant:user:query’,‘tenant:tenant:user:add’)”)

参考 SpEL 表达式注解鉴权

相关文章:

  • Linux-顺序队列练习-链式队列-树
  • cocos:从@ccclass装饰器到组件化开发
  • 大模型在舌癌预测及治疗方案制定中的应用研究
  • 软考中级网络工程师第六章网互联与互联网
  • VectorBT:Python量化交易策略开发与回测评估详解
  • sklearn基础教程
  • 【AVRCP】蓝牙链路控制器(LC)与AVRCP互操作性要求深度解析
  • 希尔排序中的Hibbard序列
  • AI大白话(四):自然语言处理——AI是如何理解和生成人类语言的?
  • 自动化测试框架详解
  • 车载软件架构 --- AUTOSAR AP/CP中诊断的区别
  • Python functools 模块的 @lru_cache 装饰器介绍
  • wps字符很分散
  • 【STM32】SPI通信协议W25Q64Flash存储器芯片(学习笔记)
  • OSS Browser2.0安装使用(阿里云对象存储OSS 图形化界面工具2.0版本)
  • 集成学习(下):Stacking集成方法
  • iPaaS集成平台安全通信的挑战与保障策略
  • MyBatis之参数传递
  • 网络故障排查指南:分治法与排除法结合的分层诊断手册
  • Diamond软件的使用--(5)查看原语
  • 菲律宾中期选举初步结果出炉,杜特尔特家族多人赢得地方选举
  • 西北大学副校长成陕西首富?旗下巨子生物去年净利超20亿,到底持股多少
  • 中国恒大:清盘人向香港高等法院申请撤回股份转让
  • 上海现有超12.3万名注册护士,本科及以上学历占一半
  • 93岁南开退休教授陈生玺逝世,代表作《明清易代史独见》多次再版
  • 甘肃:今年6月前,由县级党委、政府制定农村彩礼倡导性标准