SpringCloud Alibaba微服务实战十四 - SpringCloud Gateway集成Oauth2.0

本文涉及的产品
注册配置 MSE Nacos/ZooKeeper,118元/月
服务治理 MSE Sentinel/OpenSergo,Agent数量 不受限
云原生网关 MSE Higress,422元/月
简介: 导读:上篇文章我们已经抽取出了单独的认证服务,本章主要内容是让SpringCloud Gateway 集成Oauth2。

概念部分


1.png


在网关集成Oauth2.0后,我们的流程架构如上。主要逻辑如下:


1、客户端应用通过api网关请求认证服务器获取access_token http://localhost:8090/auth-service/oauth/token


2、认证服务器返回access_token


{
"access_token": "f938d0c1-9633-460d-acdd-f0693a6b5f4c",
"token_type": "bearer",
"refresh_token": "4baea735-3c0d-4dfd-b826-91c6772a0962",
"expires_in": 43199,
"scope": "web"}


3、客户端携带access_token通过API网关访问后端服务

2.png


4、API网关收到access_token后通过 AuthenticationWebFilter 对access_token认证


5、API网关转发后端请求,后端服务请求Oauth2认证服务器获取当前用户


在前面文章中我们搭建好了单独的Oauth2认证授权服务,基本功能框架都实现了,这次主要是来实现第四条,SpringCloud 整合 Oauth2 后如何进行access_token过滤校验。


代码示例

引入组件


<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId></dependency><dependency><groupId>org.springframework.security</groupId><artifactId>spring-security-oauth2-resource-server</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-oauth2</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-jdbc</artifactId></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency>


主要引入跟oauth2相关的jar包,这里还需要引入数据库相关的jar包,因为我们的token是存在数据库中,要想在网关层校验token的有效性必须先从数据库取出token。


bootstrap.yml 配置修改


spring:
application:
name: cloud-gatewaydatasource:
type: com.zaxxer.hikari.HikariDataSourceurl: jdbc:mysql://xx.0.xx.xx:3306/oauth2_config?characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=falseusername: xxxxxpassword: xxxxxxxdriver-class-name: com.mysql.jdbc.Driver


主要配置oauth2的数据库连接地址


自定义认证接口管理类


在webFlux环境下通过实现 ReactiveAuthenticationManager 接口 自定义认证接口管理,由于我们的token是存在jdbc中所以命名上就叫ReactiveJdbcAuthenticationManager


@Slf4jpublicclassReactiveJdbcAuthenticationManagerimplementsReactiveAuthenticationManager {
privateTokenStoretokenStore;
publicJdbcAuthenticationManager(TokenStoretokenStore){
this.tokenStore=tokenStore;
    }
@OverridepublicMono<Authentication>authenticate(Authenticationauthentication) {
returnMono.justOrEmpty(authentication)
                .filter(a->ainstanceofBearerTokenAuthenticationToken)
                .cast(BearerTokenAuthenticationToken.class)
                .map(BearerTokenAuthenticationToken::getToken)
                .flatMap((accessToken->{
log.info("accessToken is :{}",accessToken);
OAuth2AccessTokenoAuth2AccessToken=this.tokenStore.readAccessToken(accessToken);
//根据access_token从数据库获取不到OAuth2AccessTokenif(oAuth2AccessToken==null){
returnMono.error(newInvalidTokenException("invalid access token,please check"));
                    }elseif(oAuth2AccessToken.isExpired()){
returnMono.error(newInvalidTokenException("access token has expired,please reacquire token"));
                    }
OAuth2AuthenticationoAuth2Authentication=this.tokenStore.readAuthentication(accessToken);
if(oAuth2Authentication==null){
returnMono.error(newInvalidTokenException("Access Token 无效!"));
                    }else {
returnMono.just(oAuth2Authentication);
                    }
                })).cast(Authentication.class);
    }
}


网关层的安全配置


@ConfigurationpublicclassSecurityConfig {
privatestaticfinalStringMAX_AGE="18000L";
@AutowiredprivateDataSourcedataSource;
@AutowiredprivateAccessManageraccessManager;
/*** 跨域配置*/publicWebFiltercorsFilter() {
return (ServerWebExchangectx, WebFilterChainchain) -> {
ServerHttpRequestrequest=ctx.getRequest();
if (CorsUtils.isCorsRequest(request)) {
HttpHeadersrequestHeaders=request.getHeaders();
ServerHttpResponseresponse=ctx.getResponse();
HttpMethodrequestMethod=requestHeaders.getAccessControlRequestMethod();
HttpHeadersheaders=response.getHeaders();
headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, requestHeaders.getOrigin());
headers.addAll(HttpHeaders.ACCESS_CONTROL_ALLOW_HEADERS, requestHeaders.getAccessControlRequestHeaders());
if (requestMethod!=null) {
headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS, requestMethod.name());
                }
headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS, "true");
headers.add(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS, "*");
headers.add(HttpHeaders.ACCESS_CONTROL_MAX_AGE, MAX_AGE);
if (request.getMethod() ==HttpMethod.OPTIONS) {
response.setStatusCode(HttpStatus.OK);
returnMono.empty();
                }
            }
returnchain.filter(ctx);
        };
    }
@BeanSecurityWebFilterChainwebFluxSecurityFilterChain(ServerHttpSecurityhttp) throwsException{
//token管理器ReactiveAuthenticationManagertokenAuthenticationManager=newReactiveJdbcAuthenticationManager(newJdbcTokenStore(dataSource));
//认证过滤器AuthenticationWebFilterauthenticationWebFilter=newAuthenticationWebFilter(tokenAuthenticationManager);
authenticationWebFilter.setServerAuthenticationConverter(newServerBearerTokenAuthenticationConverter());
http                .httpBasic().disable()
                .csrf().disable()
                .authorizeExchange()
                .pathMatchers(HttpMethod.OPTIONS).permitAll()
                .anyExchange().access(accessManager)
                .and()
// 跨域过滤器                .addFilterAt(corsFilter(), SecurityWebFiltersOrder.CORS)
//oauth2认证过滤器                .addFilterAt(authenticationWebFilter, SecurityWebFiltersOrder.AUTHENTICATION);
returnhttp.build();
    }
}


这个类是SpringCloug Gateway 与 Oauth2整合的关键,通过构建认证过滤器 AuthenticationWebFilter 完成Oauth2.0的token校验。


AuthenticationWebFilter 通过我们自定义的 ReactiveJdbcAuthenticationManager 完成token校验。

我们在这里还加入了CORS过滤器,以及权限管理器 AccessManager


权限管理器


@Slf4j@ComponentpublicclassAccessManagerimplementsReactiveAuthorizationManager<AuthorizationContext> {
privateSet<String>permitAll=newConcurrentHashSet<>();
privatestaticfinalAntPathMatcherantPathMatcher=newAntPathMatcher();
publicAccessManager (){
permitAll.add("/");
permitAll.add("/error");
permitAll.add("/favicon.ico");
permitAll.add("/**/v2/api-docs/**");
permitAll.add("/**/swagger-resources/**");
permitAll.add("/webjars/**");
permitAll.add("/doc.html");
permitAll.add("/swagger-ui.html");
permitAll.add("/**/oauth/**");
permitAll.add("/**/current/get");
    }
/*** 实现权限验证判断*/@OverridepublicMono<AuthorizationDecision>check(Mono<Authentication>authenticationMono, AuthorizationContextauthorizationContext) {
ServerWebExchangeexchange=authorizationContext.getExchange();
//请求资源StringrequestPath=exchange.getRequest().getURI().getPath();
// 是否直接放行if (permitAll(requestPath)) {
returnMono.just(newAuthorizationDecision(true));
        }
returnauthenticationMono.map(auth-> {
returnnewAuthorizationDecision(checkAuthorities(exchange, auth, requestPath));
        }).defaultIfEmpty(newAuthorizationDecision(false));
    }
/*** 校验是否属于静态资源* @param requestPath 请求路径* @return*/privatebooleanpermitAll(StringrequestPath) {
returnpermitAll.stream()
                .filter(r->antPathMatcher.match(r, requestPath)).findFirst().isPresent();
    }
//权限校验privatebooleancheckAuthorities(ServerWebExchangeexchange, Authenticationauth, StringrequestPath) {
if(authinstanceofOAuth2Authentication){
OAuth2Authenticationathentication= (OAuth2Authentication) auth;
StringclientId=athentication.getOAuth2Request().getClientId();
log.info("clientId is {}",clientId);
        }
Objectprincipal=auth.getPrincipal();
log.info("用户信息:{}",principal.toString());
returntrue;
    }
}


主要是过滤掉静态资源,将来一些接口权限校验也可以放在这里。


测试


  • 通过网关调用auth-service获取 access_token

3.png


  • 在Header上添加认证访问后端服务

4.png


  • 网关过滤器进行token校验


5.png


  • 权限管理器校验

6.png


  • 去认证服务器校验当前用户

7.png


  • 返回正常结果
  • 8.png


  • 故意写错access_token,返回错误响应

9.png


  • 请求头上去掉access_token,直接返回401 Unauthorized


10.png


总结


通过以上几步我们将SpringCloud Gateway整合好了Oauth2.0,这样我们整个项目也基本完成了,后面几期再来对项目进行优化,欢迎持续关注。

目录
相关文章
|
10天前
|
分布式计算 大数据 Apache
ClickHouse与大数据生态集成:Spark & Flink 实战
【10月更文挑战第26天】在当今这个数据爆炸的时代,能够高效地处理和分析海量数据成为了企业和组织提升竞争力的关键。作为一款高性能的列式数据库系统,ClickHouse 在大数据分析领域展现出了卓越的能力。然而,为了充分利用ClickHouse的优势,将其与现有的大数据处理框架(如Apache Spark和Apache Flink)进行集成变得尤为重要。本文将从我个人的角度出发,探讨如何通过这些技术的结合,实现对大规模数据的实时处理和分析。
40 2
ClickHouse与大数据生态集成:Spark & Flink 实战
|
2月前
|
负载均衡 Java Nacos
SpringCloud基础2——Nacos配置、Feign、Gateway
nacos配置管理、Feign远程调用、Gateway服务网关
SpringCloud基础2——Nacos配置、Feign、Gateway
|
2月前
|
负载均衡 Java 网络架构
实现微服务网关:Zuul与Spring Cloud Gateway的比较分析
实现微服务网关:Zuul与Spring Cloud Gateway的比较分析
91 5
|
24天前
|
Dart Android开发
鸿蒙Flutter实战:03-鸿蒙Flutter开发中集成Webview
本文介绍了在OpenHarmony平台上集成WebView的两种方法:一是使用第三方库`flutter_inappwebview`,通过配置pubspec.lock文件实现;二是编写原生ArkTS代码,自定义PlatformView,涉及创建入口能力、注册视图工厂、处理方法调用及页面构建等步骤。
44 0
|
2月前
|
监控 关系型数据库 MySQL
zabbix agent集成percona监控MySQL的插件实战案例
这篇文章是关于如何使用Percona监控插件集成Zabbix agent来监控MySQL的实战案例。
50 2
zabbix agent集成percona监控MySQL的插件实战案例
|
3月前
|
机器学习/深度学习 存储 前端开发
实战揭秘:如何借助TensorFlow.js的强大力量,轻松将高效能的机器学习模型无缝集成到Web浏览器中,从而打造智能化的前端应用并优化用户体验
【8月更文挑战第31天】将机器学习模型集成到Web应用中,可让用户在浏览器内体验智能化功能。TensorFlow.js作为在客户端浏览器中运行的库,提供了强大支持。本文通过问答形式详细介绍如何使用TensorFlow.js将机器学习模型带入Web浏览器,并通过具体示例代码展示最佳实践。首先,需在HTML文件中引入TensorFlow.js库;接着,可通过加载预训练模型如MobileNet实现图像分类;然后,编写代码处理图像识别并显示结果;此外,还介绍了如何训练自定义模型及优化模型性能的方法,包括模型量化、剪枝和压缩等。
49 1
|
3月前
|
JSON 数据管理 关系型数据库
【Dataphin V3.9】颠覆你的数据管理体验!API数据源接入与集成优化,如何让企业轻松驾驭海量异构数据,实现数据价值最大化?全面解析、实战案例、专业指导,带你解锁数据整合新技能!
【8月更文挑战第15天】随着大数据技术的发展,企业对数据处理的需求不断增长。Dataphin V3.9 版本提供更灵活的数据源接入和高效 API 集成能力,支持 MySQL、Oracle、Hive 等多种数据源,增强 RESTful 和 SOAP API 支持,简化外部数据服务集成。例如,可轻松从 RESTful API 获取销售数据并存储分析。此外,Dataphin V3.9 还提供数据同步工具和丰富的数据治理功能,确保数据质量和一致性,助力企业最大化数据价值。
167 1
|
3月前
|
C# Windows 开发者
当WPF遇见OpenGL:一场关于如何在Windows Presentation Foundation中融入高性能跨平台图形处理技术的精彩碰撞——详解集成步骤与实战代码示例
【8月更文挑战第31天】本文详细介绍了如何在Windows Presentation Foundation (WPF) 中集成OpenGL,以实现高性能的跨平台图形处理。通过具体示例代码,展示了使用SharpGL库在WPF应用中创建并渲染OpenGL图形的过程,包括开发环境搭建、OpenGL渲染窗口创建及控件集成等关键步骤,帮助开发者更好地理解和应用OpenGL技术。
226 0
|
3月前
|
开发者 前端开发 开发框架
JSF与移动应用,开启全新交互体验!让你的Web应用轻松征服移动设备,让用户爱不释手!
【8月更文挑战第31天】在现代Web应用开发中,移动设备的普及使得构建移动友好的应用变得至关重要。尽管JSF(JavaServer Faces)主要用于Web应用开发,但结合Bootstrap等前端框架,也能实现优秀的移动交互体验。本文探讨如何在JSF应用中实现移动友好性,并通过示例代码展示具体实现方法。使用Bootstrap的响应式布局和组件可以确保JSF页面在移动设备上自适应,并提供友好的表单输入和提交体验。尽管JSF存在组件库较小和学习成本较高等局限性,但合理利用其特性仍能显著提升用户体验。通过不断学习和实践,开发者可以更好地掌握JSF应用的移动友好性,为Web应用开发贡献力量。
50 0
|
3月前
|
API UED 开发者
如何在Uno Platform中轻松实现流畅动画效果——从基础到优化,全方位打造用户友好的动态交互体验!
【8月更文挑战第31天】在开发跨平台应用时,确保用户界面流畅且具吸引力至关重要。Uno Platform 作为多端统一的开发框架,不仅支持跨系统应用开发,还能通过优化实现流畅动画,增强用户体验。本文探讨了Uno Platform中实现流畅动画的多个方面,包括动画基础、性能优化、实践技巧及问题排查,帮助开发者掌握具体优化策略,提升应用质量与用户满意度。通过合理利用故事板、减少布局复杂性、使用硬件加速等技术,结合异步方法与预设缓存技巧,开发者能够创建美观且流畅的动画效果。
77 0
下一篇
无影云桌面