开发公司SpringCloud整合Sa-Token登录认证+Gateway网关拦截

Sa-Token介绍Sa-Token 开发公司是一个轻量级 Java 开发公司权限认证框架,主要解决:登录认证权限认证单点登录OAuth2.0分布式Session会话开发公司微服务网关鉴权 开发公司等一系列权限相关问题

开发公司本文章框架使用:

SpringCloudAlibaba、SpringBoot2.1.13、sa-token1.30.0、redis

服务架构

 开始

一、开发公司首先配置服务

1、pom.xml

  1. <!-- Sa-Token 权限认证(Reactor开发公司响应式集成) -->
  2. <dependency>
  3. <groupId>cn.dev33</groupId>
  4. <artifactId>sa-token-reactor-spring-boot-starter</artifactId>
  5. <version>1.30.0</version>
  6. </dependency>
  7. <!-- Sa-Token 整合 Redis (使用jackson开发公司序列化方式) -->
  8. <dependency>
  9. <groupId>cn.dev33</groupId>
  10. <artifactId>sa-token-dao-redis-jackson</artifactId>
  11. <version>1.30.0</version>
  12. </dependency>
  13. <!--GateWay 网关-->
  14. <dependency>
  15. <groupId>org.springframework.cloud</groupId>
  16. <artifactId>spring-cloud-starter-gateway</artifactId>
  17. </dependency>

2、bootstrap.yml引入sa-token配置

  1. # Sa-Token配置
  2. sa-token:
  3. # token名称 (同时也是cookie名称)
  4. token-name: satoken
  5. # token有效期,单位秒,-1开发公司代表永不过期
  6. timeout: 2592000
  7. # token开发公司临时有效期 (开发公司指定时间内无操作就视为token过期),单位秒
  8. activity-timeout: -1
  9. # 开发公司是否允许同一账号并发登录 (为false开发公司时新登录挤掉旧登录)
  10. is-concurrent: true
  11. # 开发公司在多人登录同一账号时,是否共用一个token (为false时每次登录新建一个token)
  12. is-share: false
  13. # token风格
  14. token-style: uuid
  15. # 是否输出操作日志
  16. is-log: false
  17. # 是否从cookie中读取token
  18. is-read-cookie: false
  19. # 是否从head中读取token
  20. is-read-head: true

3、新建类SaTokenConfigure,实现网关拦截

  1. package com.frontop.meta.config;
  2. import cn.dev33.satoken.config.SaTokenConfig;
  3. import cn.dev33.satoken.context.SaHolder;
  4. import cn.dev33.satoken.reactor.context.SaReactorSyncHolder;
  5. import cn.dev33.satoken.reactor.filter.SaReactorFilter;
  6. import cn.dev33.satoken.router.SaHttpMethod;
  7. import cn.dev33.satoken.router.SaRouter;
  8. import cn.dev33.satoken.stp.StpUtil;
  9. import cn.dev33.satoken.util.SaResult;
  10. import com.frontop.meta.util.ResultJsonUtil;
  11. import org.springframework.context.annotation.Bean;
  12. import org.springframework.context.annotation.Configuration;
  13. import org.springframework.context.annotation.Primary;
  14. import org.springframework.web.server.ServerWebExchange;
  15. /**
  16. * @author YangBoss
  17. * @title: SaTokenConfigure
  18. * @projectName meta
  19. * @description: TODO
  20. * @date 2022/8/18 10:12
  21. */
  22. @Configuration
  23. public class SaTokenConfigure {
  24. // 注册 Sa-Token全局过滤器
  25. @Bean
  26. public SaReactorFilter getSaReactorFilter() {
  27. return new SaReactorFilter()
  28. // 拦截地址
  29. .addInclude("/**")
  30. // 开放地址
  31. .addExclude("/favicon.ico")
  32. // 鉴权方法:每次访问进入
  33. .setAuth(obj -> {
  34. // 登录校验 -- 拦截所有路由,并排除/user/doLogin 用于开放登录
  35. SaRouter.match("/**", "/meta-auth/phoneLogin", r -> StpUtil.checkLogin());
  36. // 角色认证 -- 拦截以 admin 开头的路由,必须具备 admin 角色或者 super-admin 角色才可以通过认证
  37. SaRouter.match("/admin/**", r -> StpUtil.checkRoleOr("admin", "super-admin"));
  38. // 权限认证 -- 不同模块, 校验不同权限
  39. SaRouter.match("/meta-system/**", r -> StpUtil.checkPermission("system-no"));
  40. SaRouter.match("/admin/**", r -> StpUtil.checkPermission("admin"));
  41. SaRouter.match("/goods/**", r -> StpUtil.checkPermission("goods"));
  42. SaRouter.match("/orders/**", r -> StpUtil.checkPermission("orders"));
  43. })
  44. // 异常处理方法:每次setAuth函数出现异常时进入
  45. .setError(e -> {
  46. // 设置错误返回格式为JSON
  47. ServerWebExchange exchange = SaReactorSyncHolder.getContext();
  48. exchange.getResponse().getHeaders().set("Content-Type", "application/json; charset=utf-8");
  49. // return new ResultJsonUtil().fail(e.getMessage());
  50. return SaResult.error(e.getMessage());
  51. })
  52. .setBeforeAuth(obj -> {
  53. // ---------- 设置跨域响应头 ----------
  54. SaHolder.getResponse()
  55. // 允许指定域访问跨域资源
  56. .setHeader("Access-Control-Allow-Origin", "*")
  57. // 允许所有请求方式
  58. .setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE")
  59. // 有效时间
  60. .setHeader("Access-Control-Max-Age", "3600")
  61. // 允许的header参数
  62. .setHeader("Access-Control-Allow-Headers", "*");
  63. // 如果是预检请求,则立即返回到前端
  64. SaRouter.match(SaHttpMethod.OPTIONS)
  65. .free(r -> System.out.println("--------OPTIONS预检请求,不做处理"))
  66. .back();
  67. });
  68. }
  69. }

4、新建全局异常处理类GlobalException

  1. package com.frontop.meta.config;
  2. import cn.dev33.satoken.exception.DisableLoginException;
  3. import cn.dev33.satoken.exception.NotLoginException;
  4. import cn.dev33.satoken.exception.NotPermissionException;
  5. import cn.dev33.satoken.exception.NotRoleException;
  6. import com.frontop.meta.constant.ResponseCodeConstant;
  7. import com.frontop.meta.constant.ResponseMessageConstant;
  8. import com.frontop.meta.util.ResultJsonUtil;
  9. import org.springframework.web.bind.annotation.ExceptionHandler;
  10. import org.springframework.web.bind.annotation.ResponseBody;
  11. /**
  12. * @author YangBoss
  13. * @title: GlobalException
  14. * @projectName meta
  15. * @description: 拦截全局异常类
  16. * @date 2022/8/19 15:39
  17. */
  18. public class GlobalException {
  19. // 全局异常拦截(拦截项目中的所有异常)
  20. @ResponseBody
  21. @ExceptionHandler
  22. public ResultJsonUtil<Object> handlerException(Exception e) {
  23. // 打印堆栈,以供调试
  24. // System.out.println("全局异常---------------");
  25. e.printStackTrace();
  26. // 不同异常返回不同状态码
  27. ResultJsonUtil<Object> re = null;
  28. if (e instanceof NotLoginException) { // 如果是未登录异常
  29. NotLoginException ee = (NotLoginException) e;
  30. re = new ResultJsonUtil().customized(
  31. ResponseCodeConstant.OAUTH_TOKEN_FAILURE,
  32. ResponseMessageConstant.OAUTH_TOKEN_MISSING,
  33. null
  34. );
  35. }
  36. else if(e instanceof NotRoleException) { // 如果是角色异常
  37. NotRoleException ee = (NotRoleException) e;
  38. re = new ResultJsonUtil().customized(
  39. ResponseCodeConstant.OAUTH_TOKEN_DENIED,
  40. "无此角色:" + ee.getRole(),
  41. null
  42. );
  43. }
  44. else if(e instanceof NotPermissionException) { // 如果是权限异常
  45. NotPermissionException ee = (NotPermissionException) e;
  46. re = new ResultJsonUtil().customized(
  47. ResponseCodeConstant.OAUTH_TOKEN_DENIED,
  48. "无此角色:" + ee.getCode(),
  49. null
  50. );
  51. }
  52. else if(e instanceof DisableLoginException) { // 如果是被封禁异常
  53. DisableLoginException ee = (DisableLoginException) e;
  54. re = new ResultJsonUtil().customized(
  55. ResponseCodeConstant.USER_LOCK,
  56. "账号被封禁:" + ee.getDisableTime() + "秒后解封",
  57. null
  58. );
  59. }
  60. else { // 普通异常, 输出:500 + 异常信息
  61. re = new ResultJsonUtil().fail(e.getMessage());
  62. }
  63. // 返回给前端
  64. return re;
  65. }
  66. }

5、新建类StpInterfaceImpl,实现获取当前账号权限角色集合

  1. package com.frontop.meta.config;
  2. import cn.dev33.satoken.stp.StpInterface;
  3. import org.springframework.stereotype.Component;
  4. import java.util.ArrayList;
  5. import java.util.List;
  6. /**
  7. * @author YangBoss
  8. * @title: StpInterfaceImpl
  9. * @projectName meta
  10. * @description: TODO
  11. * @date 2022/8/18 10:26
  12. */
  13. @Component
  14. public class StpInterfaceImpl implements StpInterface {
  15. /**
  16. *当前全部是模拟数据,真实情况使用根据loginId动态查询对应角色和权限
  17. */
  18. @Override
  19. public List<String> getPermissionList(Object loginId, String loginType) {
  20. // 返回此 loginId 拥有的权限列表
  21. List<String> strs = new ArrayList<>();
  22. strs.add("system");
  23. return strs;
  24. }
  25. @Override
  26. public List<String> getRoleList(Object loginId, String loginType) {
  27. // 返回此 loginId 拥有的角色列表
  28. List<String> strs = new ArrayList<>();
  29. strs.add("admin");
  30. return strs;
  31. }
  32. }

二、配置授权服务

1、pom.xml

  1. <!-- Sa-Token 权限认证, 在线文档:http://sa-token.dev33.cn/ -->
  2. <dependency>
  3. <groupId>cn.dev33</groupId>
  4. <artifactId>sa-token-spring-boot-starter</artifactId>
  5. <version>1.30.0</version>
  6. </dependency>
  7. <!-- Sa-Token 整合 Redis (使用jackson序列化方式) -->
  8. <dependency>
  9. <groupId>cn.dev33</groupId>
  10. <artifactId>sa-token-dao-redis-jackson</artifactId>
  11. <version>1.30.0</version>
  12. </dependency>

2、bootstarp.yml引入sa-token配置

  1. # Sa-Token配置
  2. sa-token:
  3. # token名称 (同时也是cookie名称)
  4. token-name: satoken
  5. # token有效期,单位秒,-1代表永不过期
  6. timeout: 2592000
  7. # token临时有效期 (指定时间内无操作就视为token过期),单位秒
  8. activity-timeout: -1
  9. # 是否允许同一账号并发登录 (为false时新登录挤掉旧登录)
  10. is-concurrent: true
  11. # 在多人登录同一账号时,是否共用一个token (为false时每次登录新建一个token)
  12. is-share: false
  13. # token风格
  14. token-style: uuid
  15. # 是否输出操作日志
  16. is-log: false
  17. # 是否从cookie中读取token
  18. is-read-cookie: false
  19. # 是否从head中读取token
  20. is-read-head: true

3、编写一个简单的登录

  1. package com.frontop.meta.controller;
  2. import cn.dev33.satoken.stp.StpUtil;
  3. import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
  4. import com.frontop.meta.util.ResultJsonUtil;
  5. import io.swagger.annotations.Api;
  6. import io.swagger.annotations.ApiOperation;
  7. import org.springframework.web.bind.annotation.GetMapping;
  8. import org.springframework.web.bind.annotation.PostMapping;
  9. import org.springframework.web.bind.annotation.RestController;
  10. /**
  11. * @author YangBoss
  12. * @title: UserLoginController
  13. * @projectName meta
  14. * @description: TODO
  15. * @date 2022/8/19 14:44
  16. */
  17. @RestController
  18. @Api(tags = "用户授权登录")
  19. public class UserLoginController {
  20. @ApiOperation(value = "手机+密码登录")
  21. @PostMapping("/phoneLogin")
  22. public ResultJsonUtil<Object> getAwardCount(String phone,String password) {
  23. if(phone.equals("18874288923") && password.equals("123")){
  24. StpUtil.login(1001,"PC");
  25. return new ResultJsonUtil().success(StpUtil.getTokenInfo());
  26. }
  27. return new ResultJsonUtil().fail("手机号或密码错误");
  28. }
  29. }

三、测试效果

1、启动网关服务和授权服务后调用登录接口

 redis中

 到这里简单的登录就完成了

2、在system业务服务中简单配置一个测试接口

 system业务服务中也需要引入sa-token,bootsrap.yml配置都是一样的

  1. <!-- Sa-Token 权限认证(Reactor响应式集成), 在线文档:http://sa-token.dev33.cn/ -->
  2. <dependency>
  3. <groupId>cn.dev33</groupId>
  4. <artifactId>sa-token-reactor-spring-boot-starter</artifactId>
  5. <version>1.30.0</version>
  6. </dependency>
  7. <!-- Sa-Token 整合 Redis (使用jackson序列化方式) -->
  8. <dependency>
  9. <groupId>cn.dev33</groupId>
  10. <artifactId>sa-token-dao-redis-jackson</artifactId>
  11. <version>1.30.0</version>
  12. </dependency>

3、不携带token值访问接口

 4、携带token访问 

这里报无权限的原因就是网关实现了拦截,在上面配置中网关配置了meta-system路由的权限必须使用system-no

而我们在添加权限集合时候没有该权限所以被拦截 

角色拦截配置也是类似

四、使用注解拦截

1、如果想使用注解拦截,只能写在业务服务的接口层

2、首先要在业务服务中开启注解拦截配置

  1. package com.frontop.meta;
  2. import cn.dev33.satoken.interceptor.SaAnnotationInterceptor;
  3. import org.springframework.context.annotation.Configuration;
  4. import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
  5. import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
  6. /**
  7. * @author YangBoss
  8. * @title: SaTokenConfigure
  9. * @projectName meta
  10. * @description: TODO
  11. * @date 2022/9/7 10:53
  12. */
  13. @Configuration
  14. public class SaTokenConfigure implements WebMvcConfigurer {
  15. // 注册Sa-Token的注解拦截器,打开注解式鉴权功能
  16. @Override
  17. public void addInterceptors(InterceptorRegistry registry) {
  18. // 注册注解拦截器,并排除不需要注解鉴权的接口地址 (与登录拦截器无关)
  19. registry.addInterceptor(new SaAnnotationInterceptor()).addPathPatterns("/**");
  20. }
  21. }

3、也需要配置获取角色和权限的集合类

  1. package com.frontop.meta;
  2. import cn.dev33.satoken.stp.StpInterface;
  3. import org.springframework.stereotype.Component;
  4. import java.util.ArrayList;
  5. import java.util.List;
  6. /**
  7. * @author YangBoss
  8. * @title: StpInterfaceImpl
  9. * @projectName meta
  10. * @description: TODO
  11. * @date 2022/8/18 10:26
  12. */
  13. @Component
  14. public class StpInterfaceImpl implements StpInterface {
  15. @Override
  16. public List<String> getPermissionList(Object loginId, String loginType) {
  17. // 返回此 loginId 拥有的权限列表
  18. List<String> strs = new ArrayList<>();
  19. strs.add("system-no");
  20. return strs;
  21. }
  22. @Override
  23. public List<String> getRoleList(Object loginId, String loginType) {
  24. // 返回此 loginId 拥有的角色列表
  25. List<String> strs = new ArrayList<>();
  26. strs.add("admin");
  27. return strs;
  28. }
  29. }

4、接口配置注解拦截

  1. @RestController
  2. @RequestMapping("/test")
  3. @Api(tags = "测试")
  4. public class TestContorller {
  5. @ApiOperation(value = "请求汇总",consumes = "application/json;charset=UTF-8")
  6. @RequestMapping(value = "/apiGather", method = RequestMethod.POST)
  7. @SaCheckRole("super-admin2")//必须拥有该角色可访问
  8. @SaCheckPermission("system-no")//必须拥有该权限可访问
  9. public ResultJsonUtil<Object> apiGather(){
  10. return new ResultJsonUtil().success("111");
  11. }
  12. }

5、测试效果

 

网站建设定制开发 软件系统开发定制 定制软件开发 软件开发定制 定制app开发 app开发定制 app开发定制公司 电商商城定制开发 定制小程序开发 定制开发小程序 客户管理系统开发定制 定制网站 定制开发 crm开发定制 开发公司 小程序开发定制 定制软件 收款定制开发 企业网站定制开发 定制化开发 android系统定制开发 定制小程序开发费用 定制设计 专注app软件定制开发 软件开发定制定制 知名网站建设定制 软件定制开发供应商 应用系统定制开发 软件系统定制开发 企业管理系统定制开发 系统定制开发