package com.fdkankan.manage.config; import cn.dev33.satoken.context.SaHolder; import cn.dev33.satoken.filter.SaServletFilter; import cn.dev33.satoken.jwt.StpLogicJwtForMixin; import cn.dev33.satoken.router.SaRouter; import cn.dev33.satoken.stp.StpLogic; import cn.dev33.satoken.stp.StpUtil; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import com.alibaba.nacos.common.utils.HttpMethod; import com.fdkankan.common.constant.ErrorCode; import com.fdkankan.common.exception.BusinessException; import com.fdkankan.common.response.ResultData; import com.fdkankan.redis.constant.RedisKey; import com.fdkankan.redis.util.RedisUtil; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import java.util.HashMap; @Configuration public class SaTokenConfigure { public static HashMap manageMenuUrl = new HashMap<>(); public static HashMap manageMenuId = new HashMap<>(); @Autowired RedisUtil redisUtil; // 注册Sa-Token的拦截器 @Bean public SaServletFilter getSaServletFilter() { return new SaServletFilter() // 指定 拦截路由 与 放行路由 .addInclude("/**").addExclude("/favicon.ico") // 认证函数: 每次请求执行 .setAuth(obj -> { System.out.println("---------- 进入Sa-Token全局认证 -----------"); // 登录认证 -- 拦截所有路由,并排除/user/doLogin 用于开放登录 SaRouter.match("/**", "/service/manage/login", r ->checkLogin() ); String menu = redisUtil.get(RedisKey.MANAGE_MENU); if(StringUtils.isBlank(menu)){ SaRouter.match("/**", r -> StpUtil.checkRole("super-admin")); } JSONArray menuArray = JSONObject.parseArray(menu); for (Object o : menuArray) { JSONObject jsonObject = (JSONObject) o; String url = jsonObject.getString("url"); String perm = jsonObject.getString("perms"); manageMenuId.put(jsonObject.getString("id"),jsonObject); if(StringUtils.isEmpty(url) || StringUtils.isEmpty(perm)){ continue; } SaRouter.match(url, r -> StpUtil.checkPermission(perm)); manageMenuUrl.put(jsonObject.getString("url"),jsonObject); } }) // 异常处理函数:每次认证函数发生异常时执行此函数 .setError(e -> { System.out.println("---------- 进入Sa-Token异常处理 -----------"); SaHolder.getResponse().setHeader("Content-Type", "application/json;charset=UTF-8"); return JSONObject.toJSONString(ResultData.error(-1,e.getMessage())); }) // 前置函数:在每次认证函数之前执行 .setBeforeAuth(r -> { // ---------- 设置一些安全响应头 ---------- SaHolder.getResponse() .setHeader("Access-Control-Allow-Origin", "*") .setHeader("Access-Control-Allow-Methods", "*") .setHeader("Access-Control-Max-Age", "3600") .setHeader("Access-Control-Allow-Headers", "*") .setServer("4dkk"); // 跳过对 OPTIONS 请求的检查,否则这里会鉴权失败,导致 springboot 配置的 addCorsMappings 跨域不执行 if (SaHolder.getRequest().getMethod().equals(HttpMethod.OPTIONS.toString())) { SaRouter.back(); } }); } private void checkLogin(){ if(!redisUtil.hasKey(String.format(RedisKey.TOKEN_V3,StpUtil.getTokenValue()))){ throw new BusinessException(ErrorCode.USER_NOT_LOGIN); } redisUtil.expire(String.format(RedisKey.TOKEN_V3,StpUtil.getTokenValue()),21600); StpUtil.checkLogin(); } // Sa-Token 整合 jwt //Stateless 无状态模式 纯jwt //Mixin 混入模式 jwt 与 Redis 逻辑混合 //Simple 简单模式 Token风格替换 @Bean public StpLogic getStpLogicJwt() { return new StpLogicJwtForMixin(); } }