SpringCloud整合Sa-Token登录认证+Gateway网关拦截
Sa-Token介绍:Sa-Token 是一个轻量级 Java 权限认证框架,主要解决:登录认证、权限认证、单点登录、OAuth2.0、分布式Session会话、微服务网关鉴权 等一系列权限相关问题
本文章框架使用:
SpringCloudAlibaba、SpringBoot2.1.13、sa-token1.30.0、redis
服务架构
开始
一、首先配置网关服务
1、pom.xml
<!-- Sa-Token 权限认证(Reactor响应式集成) --><dependency><groupId>cn.dev33</groupId><artifactId>sa-token-reactor-spring-boot-starter</artifactId><version>1.30.0</version></dependency><!-- Sa-Token 整合 Redis (使用jackson序列化方式) --><dependency><groupId>cn.dev33</groupId><artifactId>sa-token-dao-redis-jackson</artifactId><version>1.30.0</version></dependency><!--GateWay 网关--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-gateway</artifactId></dependency>
2、bootstrap.yml引入sa-token配置
# Sa-Token配置
sa-token:# token名称 (同时也是cookie名称)token-name: satoken# token有效期,单位秒,-1代表永不过期timeout: 2592000# token临时有效期 (指定时间内无操作就视为token过期),单位秒activity-timeout: -1# 是否允许同一账号并发登录 (为false时新登录挤掉旧登录)is-concurrent: true# 在多人登录同一账号时,是否共用一个token (为false时每次登录新建一个token)is-share: false# token风格token-style: uuid# 是否输出操作日志is-log: false# 是否从cookie中读取tokenis-read-cookie: false# 是否从head中读取tokenis-read-head: true
3、新建类SaTokenConfigure,实现网关拦截
package com.frontop.meta.config;import cn.dev33.satoken.config.SaTokenConfig;
import cn.dev33.satoken.context.SaHolder;
import cn.dev33.satoken.reactor.context.SaReactorSyncHolder;
import cn.dev33.satoken.reactor.filter.SaReactorFilter;
import cn.dev33.satoken.router.SaHttpMethod;
import cn.dev33.satoken.router.SaRouter;
import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.util.SaResult;
import com.frontop.meta.util.ResultJsonUtil;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.web.server.ServerWebExchange;/*** @author YangBoss* @title: SaTokenConfigure* @projectName meta* @description: TODO* @date 2022/8/18 10:12*/
@Configuration
public class SaTokenConfigure {// 注册 Sa-Token全局过滤器@Beanpublic SaReactorFilter getSaReactorFilter() {return new SaReactorFilter()// 拦截地址.addInclude("/**")// 开放地址.addExclude("/favicon.ico")// 鉴权方法:每次访问进入.setAuth(obj -> {// 登录校验 -- 拦截所有路由,并排除/user/doLogin 用于开放登录SaRouter.match("/**", "/meta-auth/phoneLogin", r -> StpUtil.checkLogin());// 角色认证 -- 拦截以 admin 开头的路由,必须具备 admin 角色或者 super-admin 角色才可以通过认证SaRouter.match("/admin/**", r -> StpUtil.checkRoleOr("admin", "super-admin"));// 权限认证 -- 不同模块, 校验不同权限SaRouter.match("/meta-system/**", r -> StpUtil.checkPermission("system-no"));SaRouter.match("/admin/**", r -> StpUtil.checkPermission("admin"));SaRouter.match("/goods/**", r -> StpUtil.checkPermission("goods"));SaRouter.match("/orders/**", r -> StpUtil.checkPermission("orders"));})// 异常处理方法:每次setAuth函数出现异常时进入.setError(e -> {// 设置错误返回格式为JSONServerWebExchange exchange = SaReactorSyncHolder.getContext();exchange.getResponse().getHeaders().set("Content-Type", "application/json; charset=utf-8");
// return new ResultJsonUtil().fail(e.getMessage());return SaResult.error(e.getMessage());}).setBeforeAuth(obj -> {// ---------- 设置跨域响应头 ----------SaHolder.getResponse()// 允许指定域访问跨域资源.setHeader("Access-Control-Allow-Origin", "*")// 允许所有请求方式.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE")// 有效时间.setHeader("Access-Control-Max-Age", "3600")// 允许的header参数.setHeader("Access-Control-Allow-Headers", "*");// 如果是预检请求,则立即返回到前端SaRouter.match(SaHttpMethod.OPTIONS).free(r -> System.out.println("--------OPTIONS预检请求,不做处理")).back();});}}
4、新建全局异常处理类GlobalException
package com.frontop.meta.config;import cn.dev33.satoken.exception.DisableLoginException;
import cn.dev33.satoken.exception.NotLoginException;
import cn.dev33.satoken.exception.NotPermissionException;
import cn.dev33.satoken.exception.NotRoleException;
import com.frontop.meta.constant.ResponseCodeConstant;
import com.frontop.meta.constant.ResponseMessageConstant;
import com.frontop.meta.util.ResultJsonUtil;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;/*** @author YangBoss* @title: GlobalException* @projectName meta* @description: 拦截全局异常类* @date 2022/8/19 15:39*/
public class GlobalException {// 全局异常拦截(拦截项目中的所有异常)@ResponseBody@ExceptionHandlerpublic ResultJsonUtil<Object> handlerException(Exception e) {// 打印堆栈,以供调试
// System.out.println("全局异常---------------");e.printStackTrace();// 不同异常返回不同状态码ResultJsonUtil<Object> re = null;if (e instanceof NotLoginException) { // 如果是未登录异常NotLoginException ee = (NotLoginException) e;re = new ResultJsonUtil().customized(ResponseCodeConstant.OAUTH_TOKEN_FAILURE,ResponseMessageConstant.OAUTH_TOKEN_MISSING,null);}else if(e instanceof NotRoleException) { // 如果是角色异常NotRoleException ee = (NotRoleException) e;re = new ResultJsonUtil().customized(ResponseCodeConstant.OAUTH_TOKEN_DENIED,"无此角色:" + ee.getRole(),null);}else if(e instanceof NotPermissionException) { // 如果是权限异常NotPermissionException ee = (NotPermissionException) e;re = new ResultJsonUtil().customized(ResponseCodeConstant.OAUTH_TOKEN_DENIED,"无此角色:" + ee.getCode(),null);}else if(e instanceof DisableLoginException) { // 如果是被封禁异常DisableLoginException ee = (DisableLoginException) e;re = new ResultJsonUtil().customized(ResponseCodeConstant.USER_LOCK,"账号被封禁:" + ee.getDisableTime() + "秒后解封",null);}else { // 普通异常, 输出:500 + 异常信息re = new ResultJsonUtil().fail(e.getMessage());}// 返回给前端return re;}
}
5、新建类StpInterfaceImpl,实现获取当前账号权限角色集合
package com.frontop.meta.config;import cn.dev33.satoken.stp.StpInterface;
import org.springframework.stereotype.Component;import java.util.ArrayList;
import java.util.List;/*** @author YangBoss* @title: StpInterfaceImpl* @projectName meta* @description: TODO* @date 2022/8/18 10:26*/
@Component
public class StpInterfaceImpl implements StpInterface {/***当前全部是模拟数据,真实情况使用根据loginId动态查询对应角色和权限*/@Overridepublic List<String> getPermissionList(Object loginId, String loginType) {// 返回此 loginId 拥有的权限列表List<String> strs = new ArrayList<>();strs.add("system");return strs;}@Overridepublic List<String> getRoleList(Object loginId, String loginType) {// 返回此 loginId 拥有的角色列表List<String> strs = new ArrayList<>();strs.add("admin");return strs;}}
二、配置授权服务
1、pom.xml
<!-- Sa-Token 权限认证, 在线文档:http://sa-token.dev33.cn/ --><dependency><groupId>cn.dev33</groupId><artifactId>sa-token-spring-boot-starter</artifactId><version>1.30.0</version></dependency><!-- Sa-Token 整合 Redis (使用jackson序列化方式) --><dependency><groupId>cn.dev33</groupId><artifactId>sa-token-dao-redis-jackson</artifactId><version>1.30.0</version></dependency>
2、bootstarp.yml引入sa-token配置
# Sa-Token配置
sa-token:# token名称 (同时也是cookie名称)token-name: satoken# token有效期,单位秒,-1代表永不过期timeout: 2592000# token临时有效期 (指定时间内无操作就视为token过期),单位秒activity-timeout: -1# 是否允许同一账号并发登录 (为false时新登录挤掉旧登录)is-concurrent: true# 在多人登录同一账号时,是否共用一个token (为false时每次登录新建一个token)is-share: false# token风格token-style: uuid# 是否输出操作日志is-log: false# 是否从cookie中读取tokenis-read-cookie: false# 是否从head中读取tokenis-read-head: true
3、编写一个简单的登录
package com.frontop.meta.controller;import cn.dev33.satoken.stp.StpUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.frontop.meta.util.ResultJsonUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;/*** @author YangBoss* @title: UserLoginController* @projectName meta* @description: TODO* @date 2022/8/19 14:44*/
@RestController
@Api(tags = "用户授权登录")
public class UserLoginController {@ApiOperation(value = "手机+密码登录")@PostMapping("/phoneLogin")public ResultJsonUtil<Object> getAwardCount(String phone,String password) {if(phone.equals("18874288923") && password.equals("123")){StpUtil.login(1001,"PC");return new ResultJsonUtil().success(StpUtil.getTokenInfo());}return new ResultJsonUtil().fail("手机号或密码错误");}}
三、测试效果
1、启动网关服务和授权服务后调用登录接口
redis中
到这里简单的登录就完成了
2、在system业务服务中简单配置一个测试接口
system业务服务中也需要引入sa-token,bootsrap.yml配置都是一样的
<!-- Sa-Token 权限认证(Reactor响应式集成), 在线文档:http://sa-token.dev33.cn/ --><dependency><groupId>cn.dev33</groupId><artifactId>sa-token-reactor-spring-boot-starter</artifactId><version>1.30.0</version></dependency><!-- Sa-Token 整合 Redis (使用jackson序列化方式) --><dependency><groupId>cn.dev33</groupId><artifactId>sa-token-dao-redis-jackson</artifactId><version>1.30.0</version></dependency>
3、不携带token值访问接口
4、携带token访问
这里报无权限的原因就是网关实现了拦截,在上面配置中网关配置了meta-system路由的权限必须使用system-no
而我们在添加权限集合时候没有该权限所以被拦截
角色拦截配置也是类似
四、使用注解拦截
1、如果想使用注解拦截,只能写在业务服务的接口层
2、首先要在业务服务中开启注解拦截配置
package com.frontop.meta;import cn.dev33.satoken.interceptor.SaAnnotationInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;/*** @author YangBoss* @title: SaTokenConfigure* @projectName meta* @description: TODO* @date 2022/9/7 10:53*/
@Configuration
public class SaTokenConfigure implements WebMvcConfigurer {// 注册Sa-Token的注解拦截器,打开注解式鉴权功能@Overridepublic void addInterceptors(InterceptorRegistry registry) {// 注册注解拦截器,并排除不需要注解鉴权的接口地址 (与登录拦截器无关)registry.addInterceptor(new SaAnnotationInterceptor()).addPathPatterns("/**");}
}
3、也需要配置获取角色和权限的集合类
package com.frontop.meta;import cn.dev33.satoken.stp.StpInterface;
import org.springframework.stereotype.Component;import java.util.ArrayList;
import java.util.List;/*** @author YangBoss* @title: StpInterfaceImpl* @projectName meta* @description: TODO* @date 2022/8/18 10:26*/
@Component
public class StpInterfaceImpl implements StpInterface {@Overridepublic List<String> getPermissionList(Object loginId, String loginType) {// 返回此 loginId 拥有的权限列表List<String> strs = new ArrayList<>();strs.add("system-no");return strs;}@Overridepublic List<String> getRoleList(Object loginId, String loginType) {// 返回此 loginId 拥有的角色列表List<String> strs = new ArrayList<>();strs.add("admin");return strs;}}
4、接口配置注解拦截
@RestController
@RequestMapping("/test")
@Api(tags = "测试")
public class TestContorller {@ApiOperation(value = "请求汇总",consumes = "application/json;charset=UTF-8")@RequestMapping(value = "/apiGather", method = RequestMethod.POST)@SaCheckRole("super-admin2")//必须拥有该角色可访问@SaCheckPermission("system-no")//必须拥有该权限可访问public ResultJsonUtil<Object> apiGather(){return new ResultJsonUtil().success("111");}}
5、测试效果
网关跨域的问题
解决:
在网关服务中创建类Cors
package com.geo.gateway.config;import org.springframework.web.cors.reactive.CorsWebFilter;import org.springframework.context.annotation.Bean;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource;
import org.springframework.web.util.pattern.PathPatternParser;
/*** @author YangBoss* @title: CorsConfig* @projectName frontop-geo-cloud* @description: TODO* @date 2023/1/30 17:57*/
public class CorsConfig {@Beanpublic CorsWebFilter corsWebFilter() {UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource (new PathPatternParser());CorsConfiguration corsConfig = new CorsConfiguration();// 允许所有请求方法corsConfig.addAllowedMethod ("*");// 允许所有域,当请求头corsConfig.addAllowedOrigin ("*");// 允许全部请求头corsConfig.addAllowedHeader ("*");// 允许携带 Cookie 等用户凭证corsConfig.setAllowCredentials (true);// 允许全部请求路径source.registerCorsConfiguration ("/**", corsConfig);return new CorsWebFilter (source);}
}
git地址:https://gitee.com/yangjial/meta.git
代码在frontop的分支,记得切换
SpringCloud整合Sa-Token登录认证+Gateway网关拦截相关推荐
- SpringBoot整合Shiro实现登录认证和授权CHCache
文章目录 一. springboot实现普通登录 1 添加依赖 2 编写配置文件 3 新建实体类和mapper 4 编写业务层代码 5 编写控制器 6 编写启动类 7 编写登录页面和主页面 二. sp ...
- springboot系列(十)springboot整合shiro实现登录认证
关于shiro的概念和知识本篇不做详细介绍,但是shiro的概念还是需要做做功课的要不无法理解它的运作原理就无法理解使用shiro: 本篇主要讲解如何使用shiro实现登录认证,下篇讲解使用shiro ...
- SpringCloud学习笔记(八)Gateway 网关
目录 一.Gateway简介 1.官网 2.是什么 3.能干嘛 4.有Zuul了怎么又出来了gateway 5.Gateway特征 6.SpringCloudGateway与Zuul的区别: 7.Zu ...
- SpringBoot整合JWT实现登录认证
目录 什么是JWT 为什么使用JWT JWT的使用场景 JWT的结构 JWT的请求流程 SpringBoot整合JWT 引入依赖 编写配置文件 token生成与验证工具类 拦截器拦截token 设置拦 ...
- 快速上手 Token 登录认证
微信搜索逆锋起笔关注后回复编程pdf 领取编程大佬们所推荐的 23 种编程资料! 作者:chrisghb 来源:https://www.jianshu.com/p/a32634a5170c 基于 Co ...
- Spring Cloud Gateway网关拦截器
参考 https://www.cnblogs.com/fdzang/p/11812348.html 1.Gateway的拦截器 我们要在项目中实现一个拦截器,需要继承两个类:GlobalFilter, ...
- SpringBoot整合Shiro实现登录认证授权操作
Apache Shiro是一个强大且易用的Java安全框架,执行身份验证.授权.密码和会话管理.使用Shiro的易于理解的API,您可以快速.轻松地获得任何应用程序,从最小的移动应用程序到最大的网络和 ...
- SpringCloud - Spring Cloud 之 Zuul和Gateway网关(十四)
Spring Cloud Gateway是Spring Cloud的一个子项目.而zuul则是Netflix公司的项目,只是Spring 将zuul集成在Spring Cloud中使用而已. 因为zu ...
- SpringBoot学习之路---简单记录整合SpringSecurity实现登录认证授权
基本上每一个项目都会有用户登录的这个功能,用户需要在登录之后才能够去访问一些资源,如果没登录的话就不能访问(403).我们可以自己编码去实现这样的业务逻辑,当然每一次都自己去编码是比较耗时的,毕竟市面 ...
最新文章
- 速度超Mask RCNN四倍,仅在单个GPU训练的实时实例分割算法 | 技术头条
- linux(gentoo)安装配置conky
- 深度干货 | 多维分析中的 UV 与 PV
- ssh根据姓名查询的时候报错java.lang.IndexOutOfBoundsException: Remember that
- 【CodeForces - 129C】Statues(思维,bfs)
- LintCode 795. 4种独特的路径(DFS)
- 搜索智能提示suggestion,附近地点搜索
- Spring高级之注解@lazy详解(超详细)
- Bailian2721 忽略大小写比较字符串大小(POJ NOI0107-16)【字符串】
- 使用免费的Open NFC simulator模拟器在BlackBerry模拟器上进行NFC程序调试
- vs2010注册码 激活方法
- 我看谷歌为啥要退出中国市场
- fNIRS | 非平稳波形的预处理方法
- VMware网络问题排查思路
- 事业单位考试计算机专业知识题库,计算机考试题库:计算机考试模拟练习题(201)...
- 季冠携“闪星服务”受邀参加2021连锁企业轻资产论坛
- win7系统没有计算机睡眠状态,如何解决win7系统无法进入睡眠状态
- 【协议】MQTT、CoAP、HTTP比较,MQTT协议优缺点
- c函数itoa和atoi实现
- Java导出带有单选款(radio)和复选框(checkbox)选中效果的word doc文档-Freemarker实现方式
热门文章
- 怎样把本地文档共享至服务器上,利用云服务器共享本地文件
- Combining Word and Entity Embeddings for Entity Linking
- 数据结构(1)—— 数据结构的三大结构
- Springboot毕业设计管理系统
- 临门一脚 | 技术水平一般的程序员如何准备面试
- 《Designing and Training of A Dual CNN for Image Denoising》阅读笔记
- C/C++框架和第三方库
- 计算机中硬盘和移动硬盘的区别,笔记本硬盘和移动硬盘有什么区别
- Wilcoxon signed rank sum test 检验
- Android Studio下拉菜单