首页 > 其他分享 >基于 COLA 架构的 Spring Cloud Alibaba(八) Spring Authorization Server

基于 COLA 架构的 Spring Cloud Alibaba(八) Spring Authorization Server

时间:2023-10-09 13:03:57浏览次数:32  
标签:http spring mall server token Spring oauth Alibaba Authorization

在前面的篇章中,我们介绍了账户服务、商品服务、订单服务、网关服务的搭建,这些服务统称为资源服务。目前这些资源服务都是未受保护的,访问他们是不需要进行认证授权的,这样毫无安全性可言。这一篇,我们将介绍如何对我们的服务资源进行保护,以及如何使用 Spring Authorization Server 进行认证授权。

1. 关于 Spring Authorization Server

Spring Authorization Server 是一个框架,它提供了 OAuth 2.1 和 OpenID Connect 1.0 规范以及其他相关规范的实现。它建立在 Spring Security 之上,为构建 OpenID Connect 1.0 身份提供者和 OAuth2 授权服务器产品提供了一个安全、轻量级和可定制的基础。关于 Spring Authorization Server 更多的介绍,可以阅读本人的写的 Spring Authorization Server 系列文章(文章地址)或参考 Spring Authorization Server 官网(官网地址)。

2. 前后端交互流程

本篇涉及到前端应用、认证服务器、资源服务器的交互,时序图如下。

基于 COLA 架构的 Spring Cloud Alibaba(八) Spring Authorization Server_Spring Boot3

3. 认证服务器搭建

由于认证服务器只负责认证授权,不承担过多的业务处理,因此认证服务器的工程架构,我们采用基于 Spring Boot 的 MVC 架构即可。本篇认证服务器的代码,直接取自本人《Spring Authorization Server (十一)单点登录-SSO》这一篇中的 spring-oauth-sso-server 代码进行修改(主要修改 pom.xml、application.yml 两个文件),建议读者先去阅读该篇文章。

认证服务器工程名称取名为:mall-oauth-server。

3.1. pom.xml

pom.xml 文件修改后,内容如下。

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.example</groupId>
        <artifactId>mall-demo</artifactId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <artifactId>mall-oauth-server</artifactId>
    <name>mall-oauth-server</name>
    <description>认证服务器</description>
    <packaging>jar</packaging>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <springframework.version>4.0.0</springframework.version>
        <spring-boot.version>3.0.2</spring-boot.version>
        <oauth2-server.version>1.1.1</oauth2-server.version>
        <spring-cloud.version>2022.0.0</spring-cloud.version>
        <spring-cloud-alibaba.version>2022.0.0.0</spring-cloud-alibaba.version>
    </properties>

    <dependencies>
        <!--spring-boot-starter-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
            <version>${spring-boot.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>${spring-boot.version}</version>
        </dependency>
        <!--nacos注册中心客户端-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
            <version>${spring-cloud-alibaba.version}</version>
        </dependency>
        <!-- nacos配置中心-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
            <version>${spring-cloud-alibaba.version}</version>
        </dependency>
        <!-- 2020.X.X版本官方重构了bootstrap引导配置的加载方式,需要添加以下依赖 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-bootstrap</artifactId>
            <version>${springframework.version}</version>
        </dependency>
        <!--2020版本以后就已经移除了对ribbon的支持,而是使用LoadBalancer-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-loadbalancer</artifactId>
            <version>${springframework.version}</version>
        </dependency>
        <!--Spring Authorization Server-->
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-oauth2-authorization-server</artifactId>
            <version>${oauth2-server.version}</version>
        </dependency>
        <!--添加spring security cas支持-->
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-cas</artifactId>
            <version>6.1.1</version>
        </dependency>
        <!--lombok-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.26</version>
        </dependency>
        <!--mysql-->
        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
            <version>8.0.33</version>
        </dependency>
        <!--阿里数据库连接池 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.2.16</version>
        </dependency>
        <!-- mybatis-plus 3.5.3及以上版本 才支持 spring boot 3-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.5.3.1</version>
        </dependency>
        <!-- spring-boot-starter-thymeleaf -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
            <version>3.1.1</version>
        </dependency>
        <!-- webjars-locator-core -->
        <dependency>
            <groupId>org.webjars</groupId>
            <artifactId>webjars-locator-core</artifactId>
            <version>0.53</version>
        </dependency>
        <!-- bootstrap:5.2.3 -->
        <dependency>
            <groupId>org.webjars</groupId>
            <artifactId>bootstrap</artifactId>
            <version>5.2.3</version>
        </dependency>
        <!-- jquery:3.6.4 -->
        <dependency>
            <groupId>org.webjars</groupId>
            <artifactId>jquery</artifactId>
            <version>3.6.4</version>
        </dependency>
    </dependencies>
  

</project>

上面 pom.xml 文件主要增加引入 Spring Cloud Alibaba 相关依赖。

3.2. application.yml

将 application.yml 改名为 bootstrap.yml,内容如下。

server:
  port: 7010
spring:
  application:
    name: mall-oauth-server
  cloud:
    nacos:
      discovery:
        server-addr: ${NACOS_ADDR}
        namespace: ${NACOS_NAMESPACE}
        group: mall
      config:
        server-addr: ${NACOS_ADDR}
        namespace: ${NACOS_NAMESPACE}
        file-extension: yaml
        group: mall
        extension-configs:
          - data-id: datasource.yaml
            group: mall
            refresh: true

这里给认证服务器分配 7010 端口,bootstrap.yml、datasource.yaml 文件中的参数配置在 bootstrap.properties 文件中,内容如下。

#nacos服务地址
NACOS_ADDR=127.0.0.1:8848
#nacos名称空间
NACOS_NAMESPACE=dev
#数据库名称
DB_NAME=mall-oauth

其中,mall-oauth 数据库,为《Spring Authorization Server (十一)单点登录-SSO》一篇中的数据库:oauth-server。

3.3. 工程结构

mall-oauth-server 项目结构如下所示。

基于 COLA 架构的 Spring Cloud Alibaba(八) Spring Authorization Server_COLA_02

3.4. 网关配置

mall-web-gateway.yaml 添加认证服务器配置信息,内容如下。

spring:
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true
      routes:
        - id: mall-account-service
          uri: lb://mall-account-service
          predicates:
            - Path=/web/v1/account/**
        - id: mall-product-service
          uri: lb://mall-product-service
          predicates:
            - Path=/web/v1/product/**
        - id:  mall-order-service
          uri: lb://mall-order-service
          predicates:
            - Path=/web/v1/order/**
        - id:  mall-oauth-server-browser
          uri: http://spring-oauth-server:7010
          predicates:
            - Path=/oauth2/authorize,/activate
        - id:  mall-oauth-server
          uri: lb://mall-oauth-server
          predicates:
            - Path=/oauth2/**,/userinfo

这里添加 http://spring-oauth-server:7010 和 lb://mall-oauth-server 两个 uri,主要用以区别浏览器和 restful 接口的请求。对于 OAuth 2.1 中的授权码模式、设备授权码模式,都涉及到浏览器登录交互,这是基于 session 的操作,如果配置成 lb://mall-oauth-server,将会导致 lb://mall-oauth-server 获取的 ip 地址与认证服务器实际的 ip 地址不一致,从而造成登录失败。

4. 认证服务器测试

搭建好认证服务器后,我们先对认证服务器做一下测试。

给 mall-oauth 数据库中的 oauth2_registered_client 客户端表添加一条客户端信息如下。

INSERT INTO `mall-oauth`.`oauth2_registered_client` (`id`, `client_id`, `client_id_issued_at`, `client_secret`, `client_secret_expires_at`, `client_name`, `client_authentication_methods`, `authorization_grant_types`, `redirect_uris`, `post_logout_redirect_uris`, `scopes`, `client_settings`, `token_settings`) VALUES ('d84e9e7c-abb1-46f7-bb0f-4511af362cb1', 'gateway-client-id', '2023-07-12 07:33:42', '$2a$10$.J0Rfg7y2Mu8AN8Dk2vL.eBFa9NGbOYCPOAFEw.QhgGLVXjO7eFDC', NULL, '客户端-网关服务', 'none,client_secret_basic', 'refresh_token,authorization_password,authorization_mobile,authorization_code,client_credentials,urn:ietf:params:oauth:grant-type:device_code', 'http://www.baidu.com', 'http://spring-oauth-server:7010', 'openid,profile', '{\"@class\":\"java.util.Collections$UnmodifiableMap\",\"settings.client.require-proof-key\":false,\"settings.client.require-authorization-consent\":true}', '{\"@class\":\"java.util.Collections$UnmodifiableMap\",\"settings.token.reuse-refresh-tokens\":true,\"settings.token.id-token-signature-algorithm\":[\"org.springframework.security.oauth2.jose.jws.SignatureAlgorithm\",\"RS256\"],\"settings.token.access-token-time-to-live\":[\"java.time.Duration\",1800.000000000],\"settings.token.access-token-format\":{\"@class\":\"org.springframework.security.oauth2.server.authorization.settings.OAuth2TokenFormat\",\"value\":\"self-contained\"},\"settings.token.refresh-token-time-to-live\":[\"java.time.Duration\",3600.000000000],\"settings.token.authorization-code-time-to-live\":[\"java.time.Duration\",300.000000000],\"settings.token.device-code-time-to-live\":[\"java.time.Duration\",300.000000000]}');

启动 mall-oauth-server 服务,看到 Nacos 已经注册上来了。

基于 COLA 架构的 Spring Cloud Alibaba(八) Spring Authorization Server_Spring Cloud Alibaba_03

以下测试均采用网关端口 7020 发起,通过网关将请求转发到认证服务器。

4.1. 客户端模式

在 postman 中,输入如下客户端信息。

基于 COLA 架构的 Spring Cloud Alibaba(八) Spring Authorization Server_Spring Boot3_04

向认证服务器发起获取 token 请求(grant_type=client_credentials),结果如下。

基于 COLA 架构的 Spring Cloud Alibaba(八) Spring Authorization Server_Spring Boot3_05

4.2. 授权码模式

浏览器输入地址:http://localhost:7020/oauth2/authorize?response_type=code&client_id=gateway-client-id&scope=profile openid&redirect_uri=http://www.baidu.com,结果如下。

基于 COLA 架构的 Spring Cloud Alibaba(八) Spring Authorization Server_Spring Boot3_06

输入用户名:user,密码:123456。提交后,结果如下。

基于 COLA 架构的 Spring Cloud Alibaba(八) Spring Authorization Server_Spring Cloud Alibaba_07

勾选授权,提交后,结果如下。

基于 COLA 架构的 Spring Cloud Alibaba(八) Spring Authorization Server_Spring Cloud Alibaba_08


将获取到的 code,使用 postman 向地址:http://spring-oauth-server:7020/oauth2/token,发起获取 token 请求,参数如下。

基于 COLA 架构的 Spring Cloud Alibaba(八) Spring Authorization Server_Spring Boot3_09

基于 COLA 架构的 Spring Cloud Alibaba(八) Spring Authorization Server_OAuth2.1_10

认证服务器返回结果如下。

基于 COLA 架构的 Spring Cloud Alibaba(八) Spring Authorization Server_Spring Boot3_11

4.3. 设备授权码模式

使用 postman 认证服务器向地址:http://spring-oauth-server:7020/oauth2/device_authorization?client_id=gateway-client-id&scope=openid profile ,发起获取设备授权码请求,结果如下。

基于 COLA 架构的 Spring Cloud Alibaba(八) Spring Authorization Server_Spring Boot3_12

在浏览器中打开认证服务器返回的地址:http://spring-oauth-server:7010/activate,结果如下。

基于 COLA 架构的 Spring Cloud Alibaba(八) Spring Authorization Server_COLA_13

输入用户名:user,密码:123456。提交后,结果如下。

基于 COLA 架构的 Spring Cloud Alibaba(八) Spring Authorization Server_Spring Boot3_14

输入认证服务器返回的用户码:VMRD-ZLSK。提交后,结果如下。

基于 COLA 架构的 Spring Cloud Alibaba(八) Spring Authorization Server_COLA_15

勾选授权,提交后,结果如下。

基于 COLA 架构的 Spring Cloud Alibaba(八) Spring Authorization Server_Spring Cloud_16

使用认证服务器返回的 device_code 向认证服务器发起获取 token 请求,结果如下。

基于 COLA 架构的 Spring Cloud Alibaba(八) Spring Authorization Server_OAuth2.1_17

4.4. 自定义密码模式

在 postman 中,输入如下信息。

基于 COLA 架构的 Spring Cloud Alibaba(八) Spring Authorization Server_OAuth2.1_18

基于 COLA 架构的 Spring Cloud Alibaba(八) Spring Authorization Server_Spring Boot3_19

向认证服务器,发起获取 token 请求,结果如下。

基于 COLA 架构的 Spring Cloud Alibaba(八) Spring Authorization Server_OAuth2.1_20

4.5. refresh_token 模式

在 postman 中,输入如下客户端信息。

基于 COLA 架构的 Spring Cloud Alibaba(八) Spring Authorization Server_OAuth2.1_21

使用上面密码模式中获取到的 refresh_token 向认证服务器发起获取 token 请求(grant_type=refresh_token),结果如下。

基于 COLA 架构的 Spring Cloud Alibaba(八) Spring Authorization Server_OAuth2.1_22

5. 资源服务器改造

这里资源服务器包括网关服务、账户服务、商品服务、订单服务。其中,账户服务、商品服务、订单服务,我们称为应用服务。

5.1. 网关服务

pom.xml 文件,添加如下依赖。

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
  <version>${spring-boot.version}</version>
</dependency>

mall-web-gateway.yaml 文件添加如下依赖。

spring:
  security:
    oauth2:
      resource-server:
        jwt:
          issuer-uri: http://spring-oauth-server:7010
logging:
  level:
    org.springframework.security: trace

创建 org.example.gateway.config 包目录,在该目录下添加 AuthorizationClientConfig 文件,内容如下。

@Configuration
@EnableWebFluxSecurity
@EnableReactiveMethodSecurity
public class AuthorizationClientConfig {

    @Bean
    public SecurityWebFilterChain authorizationClientSecurityFilterChain(ServerHttpSecurity http) throws Exception {

        //uri放行
        String[] ignoreUrls = new String[]{"/oauth2/**","/*.html","/favicon.ico","/webjars/**","/v3/api-docs/swagger-config","/*/v3/api-docs**"};
        //禁用csrf与cors
        http.csrf().disable();
        http.cors().disable();
        //客户端设置
        http
                .authorizeExchange(authorize ->
                        authorize.pathMatchers(ignoreUrls).permitAll()
                                //其他请求,需要认证
                                .anyExchange().authenticated()
                );
        http
                //资源服务器会向 http://spring-oauth-server:7010 发起 token 校验
                .oauth2ResourceServer(oauth2 -> oauth2
                        .jwt(Customizer.withDefaults())

                );
        return http.build();
    }
}

5.2. 应用服务

如果已经在网关服务做了 token 校验,且应用服务器仅在内网之间进行通信,不对外暴露的话,可以不用添加 spring-boot-starter-oauth2-resource-server 再进行一次远程认证,这样可以提高接口处理效率。如果网关服务不做 token 校验,那么每个应用服务就必须在各自的服务上对 token 进行认证。由于网关服务是基于 WebFlux 的,而应用服务是基于 WebMvc 的,因此,在应用服务中集成 spring-boot-starter-oauth2-resource-server 时,添加 AuthorizationClientConfig 的内容与网关服务有细微的差别。应用服务的 AuthorizationClientConfig 内容如下。

@Configuration
@EnableWebSecurity
@EnableMethodSecurity(jsr250Enabled = true, securedEnabled = true)
public class AuthorizationClientConfig {

	@Bean
	public SecurityFilterChain securityFilterChain(HttpSecurity http)
			throws Exception {

		//uri放行
		String[] ignoreUrls = new String[]{"/*.html","/favicon.ico","/webjars/**","/*/v3/api-docs**","/v3/api-docs/**"};
		http.authorizeHttpRequests(authorize ->
						authorize.requestMatchers(ignoreUrls).permitAll()
								 //其他请求,需要认证
								.anyRequest().authenticated()
				);

		http
                 //资源服务器会向 http://spring-oauth-server:7010 发起 token 校验
				.oauth2ResourceServer(oauth2 -> oauth2
								.jwt(Customizer.withDefaults())

				);
		return http.build();

	}
}

6. 交互流程测试

启动认证服务、网关服务、账户服务、商品服务、订单服务,对前后端交互流程进行测试。以账户服务为例,我们来测试一下”根据 id 查询账户信息“接口。

6.1. 不传 access_token

6.1.1. 通过网关访问

在 postman 中输入地址:http://localhost:7020/web/v1/account/queryById/1693333896005545986,不传 token,向网关服务发起接口请求,结果如下。

基于 COLA 架构的 Spring Cloud Alibaba(八) Spring Authorization Server_Spring Cloud_23

可以看到,返回 401 状态。

6.1.2. 直接访问应用

在 postman 中输入地址:http://localhost:7030/web/v1/account/queryById/1693333896005545986,不传 token,向账户服务发起接口请求,结果如下。

基于 COLA 架构的 Spring Cloud Alibaba(八) Spring Authorization Server_OAuth2.1_24

可以看到,同样也是返回 401 状态。

6.2. 传入 access_token

6.2.1. 通过网关访问

在 postman 中输入地址:http://localhost:7020/web/v1/account/queryById/1693333896005545986,传入 token,向网关服务发起接口请求,结果如下。

基于 COLA 架构的 Spring Cloud Alibaba(八) Spring Authorization Server_OAuth2.1_25

可以看到,正常返回接口数据。

6.2.2. 直接访问应用

在 postman 中输入地址:http://localhost:7030/web/v1/account/queryById/1693333896005545986,传入 token,向账户服务发起接口请求,结果如下。

基于 COLA 架构的 Spring Cloud Alibaba(八) Spring Authorization Server_COLA_26

可以看到,同样正常返回接口数据。

7. 总结

本篇先用时序图介绍了前端应用、认证服务器、资源服务器的交互流程。接着,介绍了认证服务器的搭建和测试。然后,介绍了资源服务器的改造,以达到对资源服务器的访问进行资源保护效果。最后对前端应用、认证服务器、资源服务器的交互流程进行了测试验证。

标签:http,spring,mall,server,token,Spring,oauth,Alibaba,Authorization
From: https://blog.51cto.com/u_15268610/7772257

相关文章

  • Spring ApplicationContext 是如何被注入的
     //ERRORNoqualifyingbeanoftype'org.springframework.context.ApplicationContext'availableapplicationContext.getBean(ApplicationContext.class);//SUCCESS@ComponentpublicclassSimpleBean3{@AutowiredprivateApplicationContexta......
  • NetCore Ocelot 之 Authorization
    Ocelotsupportsclaimsbasedauthorizationwhichisrunpostauthentication.ThismeansifouhavearouteyouwanttoauthorizeyoucanaddthefollowingtoyouRouteconfiguration."RouteClaimsRequirement":{"client_role":......
  • Spring Boot WebMvcConfigurer
    SpringBootWebMvcConfigurer,它被用来确定SpringBoot全局的MVC属性,通常需要定义一个实现 WebMvcConfigurer 接口配置类,然后在此类中配置相关MVC属性。如下示例代码所示:packagecom.exception.qms.config;importorg.springframework.format.FormatterRegistry;import......
  • SpringBootWeb案例-1上
    SpringBootWeb案例前面我们已经讲解了Web前端开发的基础知识,也讲解了Web后端开发的基础(HTTP协议、请求响应),并且也讲解了数据库MySQL,以及通过Mybatis框架如何来完成数据库的基本操作。那接下来,我们就通过一个案例,来将前端开发、后端开发、数据库整合起来。而这个案例呢,就是我们......
  • SpringBootWeb案例-1 -下
    3.员工管理完成了部门管理的功能开发之后,我们进入到下一环节员工管理功能的开发。基于以上原型,我们可以把员工管理功能分为:分页查询(今天完成)带条件的分页查询(今天完成)删除员工(今天完成)新增员工(后续完成)修改员工(后续完成)那下面我们就先从分页查询功能开始学习。3.1分页查询3.1.1......
  • SpringBoot+RabbitMQ+Redis 开发一个秒杀系统,细节打满(附源码)
    一、简易版秒杀SeckillProject系统简介开发技术二、实现细节记录1、用户密码两次MD5加密2、分布式session维持会话3、异常统一处理4、页面缓存+对象缓存5、页面静态化6、内存标记+Redis预减库存+RabbitMQ异步处理7、解决超卖8、接口限流三、效果展......
  • 架构师养成记-springboot
    1.什么是springboot? (1)是一款全新的框架,目的是为简化spring应用的初始搭建和开发过程,使用特定的方式来进行配置,从而使开发人员不需要定义样板化配置,达到"开箱即用"。 (2)核心思想是:约定大于配置。 springboot所有开发细节都是根据此思想进行实现的。2.什么是约定大于配置? ......
  • Spring事务管理
    Spring事务管理1Spring事务简介【重点】1.1Spring事务作用事务作用:在数据层保障一系列的数据库操作同成功同失败Spring事务作用:在数据层或业务层保障一系列的数据库操作同成功同失败1.2案例分析Spring事务需求:实现任意两个账户间转账操作需求微缩:A账户减钱,B账户加钱分析:①:数据......
  • Spring中有哪些依赖注入的方式
    Spring中有哪些依赖注入的方式有2种实现方式:注解(如@Autowired,@Resource,@Required)配置文件(如xml)1.注解:@ComponentpublicclassMyService{privateDependencydependency;@AutowiredpublicMyService(Dependencydependency){this.d......
  • Spring事务管理
    Spring事务管理1Spring事务简介【重点】1.1Spring事务作用事务作用:在数据层保障一系列的数据库操作同成功同失败Spring事务作用:在数据层或业务层保障一系列的数据库操作同成功同失败1.2案例分析Spring事务需求:实现任意两个账户间转账操作需求微缩:A账户减钱,B账户加钱分析:①:数据......