package com.fdkankan.manage.config; import cn.dev33.satoken.context.SaHolder; import cn.dev33.satoken.exception.NotLoginException; import cn.dev33.satoken.exception.NotPermissionException; import cn.dev33.satoken.exception.NotRoleException; 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.util.SecurityUtil; import com.fdkankan.manage.common.RedisKeyUtil; import com.fdkankan.manage.common.ResultCode; import com.fdkankan.manage.exception.BusinessException; import com.fdkankan.manage.common.ResultData; import com.fdkankan.manage.service.ISysMenuService; import com.fdkankan.redis.constant.RedisKey; import com.fdkankan.redis.util.RedisUtil; import lombok.extern.slf4j.Slf4j; 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; import java.util.List; @Configuration @Slf4j public class SaTokenConfigure { public static HashMap manageMenuUrl = new HashMap<>(); public static HashMap manageMenuId = new HashMap<>(); @Autowired RedisUtil redisUtil; @Autowired ISysMenuService sysMenuService; // 注册Sa-Token的拦截器 @Bean public SaServletFilter getSaServletFilter() { return new SaServletFilter() // 指定 拦截路由 与 放行路由 .addInclude("/**").addExclude("/**/reMyselfPassword","/**/test/**","/**/inner/**","/**/feedback/h5/**") // 认证函数: 每次请求执行 .setAuth(obj -> { // 登录认证 -- 拦截所有路由,并排除/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")); return; } JSONArray menuArray = JSONObject.parseArray(menu); for (Object o : menuArray) { JSONObject jsonObject = (JSONObject) o; String url = jsonObject.getString("url"); String perm = jsonObject.getString("perms"); if(StringUtils.isEmpty(url) || StringUtils.isEmpty(perm)){ continue; } manageMenuId.put(jsonObject.getString("id"),jsonObject); manageMenuUrl.put(jsonObject.getString("url"),jsonObject); if(StpUtil.hasRole("super-admin")){ continue; } SaRouter.match(url, r -> StpUtil.checkPermission(perm)); } }) // 异常处理函数:每次认证函数发生异常时执行此函数 .setError(e -> { SaHolder.getResponse().setHeader("Content-Type", "application/json;charset=UTF-8"); ResultData aj ; if (e instanceof NotLoginException) { // 如果是未登录异常 NotLoginException ee = (NotLoginException) e; aj = ResultData.error(ResultCode.USER_NOT_LOGIN.code(),ResultCode.USER_NOT_LOGIN.message()); } else if(e instanceof NotRoleException) { // 如果是角色异常 NotRoleException ee = (NotRoleException) e; aj = ResultData.error(ResultCode.NOT_ROLE.code(),ResultCode.NOT_ROLE.message()); } else if(e instanceof NotPermissionException) { // 如果是权限异常 NotPermissionException ee = (NotPermissionException) e; aj = ResultData.error(ResultCode.NOT_PERMISSION.code(),ResultCode.NOT_PERMISSION.message()); } else if(e instanceof BusinessException) { // 如果是权限异常 BusinessException ee = (BusinessException) e; aj = ResultData.error(ee.getCode(),ee.getMessage()); } else { // 普通异常, 输出:500 + 异常信息 aj = ResultData.error(ResultCode.SYSTEM_ERROR.code(),ResultCode.SYSTEM_ERROR.message()); } return JSONObject.toJSONString(aj); }) // 前置函数:在每次认证函数之前执行 .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(RedisKeyUtil.loginToken,StpUtil.getTokenValue()))){ throw new BusinessException(ResultCode.USER_NOT_LOGIN); } redisUtil.expire(String.format(RedisKeyUtil.loginToken,StpUtil.getTokenValue()),21600); StpUtil.checkLogin(); } //Sa-Token 整合 jwt //Stateless 无状态模式 纯jwt //Mixin 混入模式 jwt 与 Redis 逻辑混合 //Simple 简单模式 Token风格替换 @Bean public StpLogic getStpLogicJwt() { return new StpLogicJwtForMixin(); } }