SaTokenConfigure.java 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. package com.fdkankan.fusion.config;
  2. import cn.dev33.satoken.context.SaHolder;
  3. import cn.dev33.satoken.exception.NotLoginException;
  4. import cn.dev33.satoken.exception.NotPermissionException;
  5. import cn.dev33.satoken.exception.NotRoleException;
  6. import cn.dev33.satoken.filter.SaServletFilter;
  7. import cn.dev33.satoken.jwt.StpLogicJwtForMixin;
  8. import cn.dev33.satoken.router.SaRouter;
  9. import cn.dev33.satoken.stp.StpLogic;
  10. import cn.dev33.satoken.stp.StpUtil;
  11. import com.alibaba.fastjson.JSONArray;
  12. import com.alibaba.fastjson.JSONObject;
  13. import com.aliyun.oss.HttpMethod;
  14. import com.fdkankan.fusion.common.ResultCode;
  15. import com.fdkankan.fusion.common.ResultData;
  16. import com.fdkankan.fusion.common.util.RedisKeyUtil;
  17. import com.fdkankan.fusion.controller.LoginController;
  18. import com.fdkankan.fusion.exception.BusinessException;
  19. import com.fdkankan.fusion.httpClient.FdService;
  20. import com.fdkankan.fusion.httpClient.response.FdkkLoginVo;
  21. import com.fdkankan.fusion.service.ITmPermissionService;
  22. import com.fdkankan.fusion.service.ITmUserService;
  23. import com.fdkankan.redis.constant.RedisKey;
  24. import com.fdkankan.redis.util.RedisUtil;
  25. import lombok.extern.slf4j.Slf4j;
  26. import org.apache.commons.lang3.StringUtils;
  27. import org.springframework.beans.factory.annotation.Autowired;
  28. import org.springframework.context.annotation.Bean;
  29. import org.springframework.context.annotation.Configuration;
  30. import java.util.HashMap;
  31. @Configuration
  32. @Slf4j
  33. public class SaTokenConfigure {
  34. @Autowired
  35. RedisUtil redisUtil;
  36. @Autowired
  37. FdService fdService;
  38. // 注册Sa-Token的拦截器
  39. @Bean
  40. public SaServletFilter getSaServletFilter() {
  41. return new SaServletFilter()
  42. // 指定 拦截路由 与 放行路由
  43. .addInclude("/**").addExclude("/**/test/**","/**/inner/**","/**/notAuth/**")
  44. // 认证函数: 每次请求执行
  45. .setAuth(obj -> {
  46. String share = SaHolder.getRequest().getHeader("share");
  47. if(StringUtils.isNotBlank(share) && "1".equals(share)){ //分享请求头
  48. return;
  49. }
  50. SaRouter.match("/sceneDownLog/list", r -> StpUtil.checkRole("admin-super"));
  51. // 登录认证 -- 拦截所有路由,并排除/user/doLogin 用于开放登录
  52. SaRouter.match("/**", "/fdLogin", r ->checkLogin() );
  53. String menu = redisUtil.get(RedisKey.MANAGE_MENU);
  54. if(StringUtils.isBlank(menu)){
  55. SaRouter.match("/**", r -> StpUtil.checkRole("admin-super"));
  56. return;
  57. }
  58. JSONArray menuArray = JSONObject.parseArray(menu);
  59. for (Object o : menuArray) {
  60. JSONObject jsonObject = (JSONObject) o;
  61. String url = jsonObject.getString("url");
  62. String perm = jsonObject.getString("perms");
  63. if(StringUtils.isEmpty(url) || StringUtils.isEmpty(perm)){
  64. continue;
  65. }
  66. if(StpUtil.hasRole("admin-super")){
  67. continue;
  68. }
  69. SaRouter.match(url, r -> StpUtil.checkPermission(perm));
  70. }
  71. })
  72. // 异常处理函数:每次认证函数发生异常时执行此函数
  73. .setError(e -> {
  74. SaHolder.getResponse().setHeader("Content-Type", "application/json;charset=UTF-8");
  75. ResultData aj ;
  76. if (e instanceof NotLoginException) { // 如果是未登录异常
  77. NotLoginException ee = (NotLoginException) e;
  78. aj = ResultData.error(ResultCode.USER_NOT_LOGIN);
  79. }
  80. else if(e instanceof NotRoleException) { // 如果是角色异常
  81. NotRoleException ee = (NotRoleException) e;
  82. aj = ResultData.error(ResultCode.NOT_PERMISSION);
  83. }
  84. else if(e instanceof NotPermissionException) { // 如果是权限异常
  85. NotPermissionException ee = (NotPermissionException) e;
  86. aj = ResultData.error(ResultCode.NOT_PERMISSION);
  87. }
  88. else if(e instanceof BusinessException) { // 如果是权限异常
  89. BusinessException ee = (BusinessException) e;
  90. aj = ResultData.error(ee.getCode(),ee.getMessage());
  91. }
  92. else { // 普通异常, 输出:500 + 异常信息
  93. aj = ResultData.error(ResultCode.SYSTEM_ERROR);
  94. }
  95. return JSONObject.toJSONString(aj);
  96. })
  97. // 前置函数:在每次认证函数之前执行
  98. .setBeforeAuth(r -> {
  99. // ---------- 设置一些安全响应头 ----------
  100. SaHolder.getResponse()
  101. .setHeader("Access-Control-Allow-Origin", "*")
  102. .setHeader("Access-Control-Allow-Methods", "*")
  103. .setHeader("Access-Control-Max-Age", "3600")
  104. .setHeader("Access-Control-Allow-Headers", "*")
  105. .setServer("4dkk");
  106. // 跳过对 OPTIONS 请求的检查,否则这里会鉴权失败,导致 springboot 配置的 addCorsMappings 跨域不执行
  107. if (SaHolder.getRequest().getMethod().equals(HttpMethod.OPTIONS.toString())) {
  108. SaRouter.back();
  109. }
  110. });
  111. }
  112. private void checkLogin(){
  113. if(!redisUtil.hasKey(String.format(RedisKeyUtil.fusionLoginToken,StpUtil.getTokenValue()))){
  114. throw new BusinessException(ResultCode.USER_NOT_LOGIN);
  115. }
  116. redisUtil.expire(String.format(RedisKeyUtil.fusionLoginToken,StpUtil.getTokenValue()),21600);
  117. if(!redisUtil.hasKey(String.format(RedisKeyUtil.fusionLoginUser,StpUtil.getLoginId()))){
  118. throw new BusinessException(ResultCode.USER_NOT_LOGIN);
  119. }
  120. String value = redisUtil.get(String.format(RedisKeyUtil.fusionLoginUser,StpUtil.getLoginId()));
  121. FdkkLoginVo fdkkLoginVo = JSONObject.parseObject(value, FdkkLoginVo.class);
  122. if(fdkkLoginVo.getTmUser().getStatus() == 0){
  123. throw new BusinessException(ResultCode.USER_NOT_LOGIN_PERM);
  124. }
  125. redisUtil.expire(String.format(RedisKeyUtil.fusionLoginUser,StpUtil.getLoginId()),21600);
  126. //校验fdtoken
  127. if(!redisUtil.hasKey(String.format(RedisKeyUtil.fdToken,fdService.getFdToken()))){
  128. throw new BusinessException(ResultCode.USER_NOT_LOGIN);
  129. }
  130. redisUtil.expire(String.format(RedisKeyUtil.fdToken,fdService.getFdToken()),21600);
  131. StpUtil.checkLogin();
  132. }
  133. //Sa-Token 整合 jwt
  134. //Stateless 无状态模式 纯jwt
  135. //Mixin 混入模式 jwt 与 Redis 逻辑混合
  136. //Simple 简单模式 Token风格替换
  137. @Bean
  138. public StpLogic getStpLogicJwt() {
  139. return new StpLogicJwtForMixin();
  140. }
  141. }