module:auth

1.添加依赖:spring-cloud-starter-security与spring-cloud-starter-oauth2

2.配置WebSecurityConfig:注入AuthenticationManager覆写configure

3.配置tokenConfig

4.授权服务器配置:AuthorizationServer extends AuthorizationServerConfigurerAdapter配置客户端详细任务,令牌端点配置

5.实现UserDetailsService,覆写loadUserByUsername(最熟悉的一集)

tips:这里return 的UserDetails对象不用自己创建,springsecurity提供了一个User类实现了UserDetails,通过建造者模式可以直接生成username,password,authorities等信息。这里如果需要多参数分发给其他module使用,建议的做法是将数据库中查出来的对象通过json转成字符串存入username,后续可以直接将username反写成具体的class

module:gateway

首先明确网关的作用:路由转发、认证、白名单放行:针对当前网关的路由进行转发,如果是白名单则直接放行,如果是需要JWT校验则需要校验JWT合法性

security中提供了认证与授权,这里我们在网关进行了认证,也就是说授权模块是在各个微服务中进行的

gateway集成springsecurity:

1.添加依赖:spring-cloud-starter-security与spring-cloud-starter-oauth2

2.添加配置:过滤器;再添加tokenConfig、securityConfig


/**
*
* @description 网关认证过滤器:这段代码主要是作为过滤器去处理一个http请求,首先是检查请求路径是否在白名单中,请求是否携带token/有没有过期等安全相关检查
*/
@Component
@Slf4j
public class GatewayAuthFilter implements GlobalFilter, Ordered { //白名单
private static List<String> whitelist = null; static {
//加载白名单
try (
InputStream resourceAsStream = GatewayAuthFilter.class.getResourceAsStream("/security-whitelist.properties");
) {
Properties properties = new Properties();
properties.load(resourceAsStream);
Set<String> strings = properties.stringPropertyNames();
whitelist= new ArrayList<>(strings); } catch (Exception e) {
log.error("加载/security-whitelist.properties出错:{}",e.getMessage());
e.printStackTrace();
}
} @Autowired
private TokenStore tokenStore; @Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
String requestUrl = exchange.getRequest().getPath().value();
AntPathMatcher pathMatcher = new AntPathMatcher();
//白名单放行
for (String url : whitelist) {
if (pathMatcher.match(url, requestUrl)) {
return chain.filter(exchange);
}
} //检查token是否存在
String token = getToken(exchange);
if (StringUtils.isBlank(token)) {
return buildReturnMono("没有认证",exchange);
}
//判断是否是有效的token
OAuth2AccessToken oAuth2AccessToken;
try {
oAuth2AccessToken = tokenStore.readAccessToken(token); boolean expired = oAuth2AccessToken.isExpired();
if (expired) {
return buildReturnMono("认证令牌已过期",exchange);
}
return chain.filter(exchange);
} catch (InvalidTokenException e) {
log.info("认证令牌无效: {}", token);
return buildReturnMono("认证令牌无效",exchange);
} } /**
* 获取token
*/
private String getToken(ServerWebExchange exchange) {
String tokenStr = exchange.getRequest().getHeaders().getFirst("Authorization");
if (StringUtils.isBlank(tokenStr)) {
return null;
}
String token = tokenStr.split(" ")[1];
if (StringUtils.isBlank(token)) {
return null;
}
return token;
}
private Mono<Void> buildReturnMono(String error, ServerWebExchange exchange) {
ServerHttpResponse response = exchange.getResponse();
String jsonString = JSON.toJSONString(new RestErrorResponse(error));
byte[] bits = jsonString.getBytes(StandardCharsets.UTF_8);
DataBuffer buffer = response.bufferFactory().wrap(bits);
response.setStatusCode(HttpStatus.UNAUTHORIZED);
response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
return response.writeWith(Mono.just(buffer));
} @Override
public int getOrder() {
return 0;
}
}
    // 假设已经从请求中获得了token
String token = getToken(exchange); // 如果token存在且不为空
if (token != null && !token.isEmpty()) {
// 创建一个新的ServerHttpRequest,并添加token到Authorization头
ServerHttpRequest mutatedRequest = exchange.getRequest().mutate()
.header("Authorization", "Bearer " + token)
.build(); // 使用ServerWebExchangeDecorator来包装原始的ServerWebExchange,并且使用修改后的请求
ServerWebExchange mutatedExchange = exchange.mutate()
.request(mutatedRequest)
.build(); return chain.filter(mutatedExchange);
}

3.配置白名单security-whitelist.properties

/media/open/**=媒资管理公开访问接口

4.在其他微服务模块中放行所有路由,并且直接通过SecurityContextHolder.getContext().getAuthentication()获取对象(因为在网关中已经校验完了,这里只负责授权)

module:others

1.包装一个SecurityUtil。SecurityContextHolder.getContext().getAuthentication().getPrincipal();即可获得具体username,然后将username转为实体类即可使用

@Slf4j
public class SecurityUtil { public static XcUser getUser() {
try {
Object principalObj = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
if (principalObj instanceof String) {
//取出用户身份信息
String principal = principalObj.toString();
//将json转成对象
XcUser user = JSON.parseObject(principal, XcUser.class);
return user;
}
} catch (Exception e) {
log.error("获取当前登录用户身份出错:{}", e.getMessage());
e.printStackTrace();
} return null;
} @Data
public static class XcUser implements Serializable { private static final long serialVersionUID = 1L; private String id; private String username; private String password; private String salt; private String name;
private String nickname;
private String wxUnionid;
private String companyId;
/**
* 头像
*/
private String userpic; private String utype; private LocalDateTime birthday; private String sex; private String email; private String cellphone; private String qq; /**
* 用户状态
*/
private String status; private LocalDateTime createTime; private LocalDateTime updateTime; } }

使用说明:上文使用了成员内部类,XcUser定义在外部类的成员位置,其不能创建独立对象,必须依靠外部类实例.new 内部类()来创建实例

SecurityUtil.XcUser user = SecurityUtil.getUser();

Q&A:

token在gateway中传递下去的?

(无oauth2集成)一般情况下我们需要修改ServerWebExchange里的ServerHttpRequest,但是ServerHttpRequest是不可变的。因此如果我们需要添加上token,就需要新建一个ServerWebExchange,重写ServerHttpRequest。

除此以外,因为我们还会将请求传递给下一个GatewayFilterChain,我们可以在这个请求传递的时候通过修改ServerWebExchange的MutableHttpRequest:

(有oauth2集成)springsecurity的过滤器链会自动处理从请求中提取token,并将其附加到上下文中,下游的过滤器会通过springsecurity的API获取他

为什么其他微服务模块能直接通过SecurityContextHolder.getContext().getAuthentication()获取对象?

在微服务中,每一个模块都有独属于自己的JVM,拥有独属于自己的线程,也就是说每个模块的SecurityContext是不一样的。当我们使用oauth2,用户通过上述gateway进行认证,并获取一个jwt将其放在request中。

当一个模块接收到一个包含oauth2令牌的http请求时,他会使用这个令牌来验证用户身份,并且基于令牌构建一个新的SecurityContext。也就是说SecurityContext的实现其实是局限于单个服务的单个线程的,跨服务的安全信息传递是由oauth2进行的

微服务集成springsecurity实现认证的更多相关文章

  1. ScalaPB(0): 找寻合适的内部系统微服务集成工具

    前一段时间我们探讨了SDP的一个基于集群的综合数据平台解决方案,由多种数据库组成,包括:JDBC, Cassandra 及MongoDB.其中Cassandra和MongoDB属于分布式数据库,可以在 ...

  2. (12)go-micro微服务JWT跨域认证

    目录 一 JWT介绍 二 JWT优缺点 三 JWT使用 1. 导包和数据定义 2.生成JWT 3.解析JWT 4.完整代码 四 最后 一 JWT介绍 JWT 英文名是 Json Web Token , ...

  3. Spring Cloud(一)简单的微服务集成Eureka

    1        Spring Cloud简介 1.1             简介 Spring Cloud项目的官方网址:https://projects.spring.io/spring-clo ...

  4. Spring cloud微服务安全实战-6-2JWT认证之认证服务改造

    首先来解决认证的问题. 1.效率低,每次认证都要去认证服务器调一次服务. 2.传递用户身份,在请求头里面, 3.服务之间传递请求头比较麻烦. jwt令牌. spring提供了工具,帮你在微服务之间传递 ...

  5. 微服务系列之授权认证(一) OAuth 2.0 和 OpenID Connect

    1.传统架构的授权认证 传统应用架构,用户使用账号密码登录后,可以使用前端cookie存储登录状态,也可以使用后端session方式存储登录状态,小应用这么做其实很高效实用,当应用需要横向扩展时,就需 ...

  6. 微服务系列之授权认证(三) JWT

    1.JWT简介 官方定义:JWT是JSON Web Token的缩写,JSON Web Token是一个开放标准(RFC 7519),它定义了一种紧凑的.自包含的方式,可以将各方之间的信息作为JSON ...

  7. Spring Cloud微服务集成配置中心

    1. 搭建Spring Cloud Config配置中心(见上一篇博客) 2. 创建微服务项目bounter-simon-app,pom文件如下: <?xml version="1.0 ...

  8. 微服务系列之授权认证(二) identity server 4

    1.简介 IdentityServer4 是为ASP.NET Core系列量身打造的一款基于 OpenID Connect 和 OAuth 2.0 认证授权框架. 官方文档:https://ident ...

  9. Devops 开发运维高级篇之Jenkins+Docker+SpringCloud微服务持续集成(上)

    Devops 开发运维高级篇之Jenkins+Docker+SpringCloud微服务持续集成(上) Jenkins+Docker+SpringCloud持续集成流程说明 大致流程说明: 1) 开发 ...

  10. Taurus.MVC 微服务框架 入门开发教程:项目集成:1、服务端:注册中心、网关(提供可运行程序下载)。

    系列目录: 本系列分为项目集成.项目部署.架构演进三个方向,后续会根据情况调整文章目录. 本系列第一篇:Taurus.MVC V3.0.3 微服务开源框架发布:让.NET 架构在大并发的演进过程更简单 ...

随机推荐

  1. ASP.NET Core SignalR .NET 客户端

    项目 2022/11/29 13 个参与者 反馈 通过 ASP.NET Core SignalR .NET 客户端库可以从 .NET 应用与 SignalR 中心进行通信. 查看或下载示例代码(如何下 ...

  2. Redis数据存储和读写

    今天工作群里,有小伙伴问了一个问题,从Redis获取的数据,一会是0,一会是OK. 这引起了我们对Redis数据存储和读写的疑问. 以下是整理的一些技术研究内容. 在 Redis 中,所有的数据存储都 ...

  3. Qt--ui的简单使用(1)

    1  说明 本文主要介绍Qt ui界面的简单使用. 参考视频:https://www.bilibili.com/video/BV1XW411x7NU?p=22 2  工程创建 创建工程时,把创建界面给 ...

  4. Spark-submit常用任务命令参数和说明

    Spark常用任务命令参数和说明 spark-submit \ --name task2018072711591669 \ --master yarn --deploy-mode client \ - ...

  5. .NET5 IIS ASP.NET CORE 部署时 HTTP Error 502.5 - ANCM Out-Of-Process Startup Failure

    .NET5 IIS ASP.NET CORE 部署时 HTTP Error 502.5 - ANCM Out-Of-Process Startup Failure 部署机器只安装了dotnet-hos ...

  6. Vue学习:15.组件化开发

    组件化开发 组件化开发是一种软件开发方法,它将应用程序拆分成独立的.可重用的模块,每个模块都被称为组件.这些组件可以独立开发.测试.维护和部署,从而提高了代码的可维护性.可扩展性和复用性.在前端开发中 ...

  7. 重学前端 - react 项目第一节:创建react 项目

    重学前端 - react 项目第一节:创建react 项目 简介:之前一直使用的都是 vue 全家桶开发项目,现在在新的项目上开始使用react开发. 现在开始在重新学习一下 react 相关技术. ...

  8. 支付宝 返回的form如何在前端打开

    支付宝支付时返回了一段标签标签大概是 <form></form><script></script> 试了innerHtml怎么试都不能用,是那种直接把字 ...

  9. python selenium.remote远程连接时间达10分钟

    问题: 在机器A搭建了selenium-grid的环境,hub以4444端口号启动,并在4444下注册了子node,端口4445,浏览器配置chrome 使用代码进行远程连接,并创建会话: 传入的se ...

  10. 忘记Linux密码这样破解

    忘记了Linux的密码该怎么办呢?有人想到重装系统.我想说除非你不想干了! 在这里使用CentOS7来教大家怎么 破解Linux的密码 (不能知道原来的密码,但是可以强行修改) 1.在grub引导界面 ...