基于Spring Security 6的OAuth2 系列之三 - 客户端--基于Spring Security演示授权码模式

之所以想写这一系列,是因为之前工作过程中使用Spring Security OAuth2搭建了网关和授权服务器,但当时基于spring-boot 2.3.x,其默认的Spring Security是5.3.x。之后新项目升级到了spring-boot 3.3.0,结果一看Spring Security也升级为6.3.0。无论是Spring Security的风格和以及OAuth2都做了较大改动,里面甚至将授权服务器模块都移除了,导致在配置同样功能时,花费了些时间研究新版本的底层原理,这里将一些学习经验分享给大家。

注意由于框架不同版本改造会有些使用的不同,因此本次系列中使用基本框架是 spring-boo-3.3.0(默认引入的Spring Security是6.3.0),JDK版本使用的是19,本系列OAuth2的代码采用Spring Security6.3.0框架,所有代码都在oauth2-study项目上:https://github.com/forever1986/oauth2-study.git

我们知道OAuth 2.0只是一个协议框架,定义了流程并没有实现。好在目前市面上已经有很多实现的,比如Spring Security、Keycloak、Okta等等。 说明:我们本系列就是使用Spring Security 6 框架,如果对Spring Security 6不熟悉的,强烈要求先去了解我写的《Spring Security6 系列》,这样对后面章节才会上手容易

1 Spring Security 6 实现

代码参考lesson01子模块

1.1 项目准备

1)在上面我们已经注册了Gitee的应用,因此这里沿用上面已经注册的到的应用oauth-demo(如果没看到系列2的,请移步先看系列2

2)上面你已经将你的应用注册到Gitee上面,现在,你需要做的是新建一个父项目oauth2-study,其只是作为一个统一引入依赖版本,不做任何代码(该父项目只是为了后续课程做的依赖管理),其pom做一下依赖管理:

注意:这里引入多个依赖只是为了后面其它演示使用

<properties>
    <maven.compiler.source>19</maven.compiler.source>
    <maven.compiler.target>19</maven.compiler.target>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <spring-boot.version>3.3.0</spring-boot.version>
    <spring-cloud.version>2023.0.3</spring-cloud.version>
    <spring-cloud-alibaba.version>2023.0.1.0</spring-cloud-alibaba.version>
    <commons-pool2.version>2.12.0</commons-pool2.version>
    <jaxb-api.version>2.3.1</jaxb-api.version>
    <jjwt.version>0.9.0</jjwt.version>
    <lombok.version>1.18.36</lombok.version>
    <mybatis-plus.version>3.5.5</mybatis-plus.version>
    <mysql.version>8.0.19</mysql.version>
    <druid.version>1.2.9</druid.version>
    <fastjson.version>1.2.83</fastjson.version>
</properties>


<dependencyManagement>
    <dependencies>
        <!-- 引入spring boot依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-dependencies</artifactId>
            <version>${spring-boot.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
        <!-- 引入spring cloud alibaba依赖-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-alibaba-dependencies</artifactId>
            <version>${spring-cloud-alibaba.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
        <!-- 引入spring cloud依赖-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>${spring-cloud.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
        <!-- lombok依赖,用于get/set的简便-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>${lombok.version}</version>
        </dependency>
        <!-- mysql依赖,用于连接mysql数据库-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>${mysql.version}</version>
        </dependency>
        <!-- mybatis-plus依赖,用于使用mybatis-plus-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-spring-boot3-starter</artifactId>
            <version>${mybatis-plus.version}</version>
            <type>jar</type>
        </dependency>
        <!-- jjwt依赖,用于使用JWT-->
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <version>${jjwt.version}</version>
        </dependency>
        <!-- jaxb-api依赖,在java17之后,被移除了,但是在做JWT解析时需要使用-->
        <dependency>
            <groupId>javax.xml.bind</groupId>
            <artifactId>jaxb-api</artifactId>
            <version>${jaxb-api.version}</version>
        </dependency>
        <!-- pool2和druid依赖,用于mysql连接池-->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
            <version>${commons-pool2.version}</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>${druid.version}</version>
        </dependency>
        <!-- fastjson依赖,用于json转换-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>${fastjson.version}</version>
        </dependency>
    </dependencies>
</dependencyManagement>

<!-- maven仓库 -->
<repositories>
    <repository>
        <id>central</id>
        <url>https://maven.aliyun.com/repository/central</url>
        <releases>
            <enabled>true</enabled>
        </releases>
        <snapshots>
            <enabled>true</enabled>
        </snapshots>
    </repository>
</repositories>

1.2 代码实现

1)新增lesson01子模块,其pom引入如下:

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-oauth2-client</artifactId>
    </dependency>
</dependencies>

2)在resources目录下,创建application.yml文件,内容如下:

spring:
  application:
    name: oauth-client

  security:
    oauth2:
      client:
        registration:
          gitee:
            # 注册应用后的Client ID
            clientId: **换成你的clientId:XXXXXXXXXXXX**
            # 注册应用后的Client Secret
            clientSecret: **换成你的clientSecret:XXXXXXXXXXXX**
            # 授权码模式
            authorizationGrantType: authorization_code
            # 回调地址
            redirectUri: http://localhost:8080/login/oauth2/code/gitee
            # 授权访问
            scope:
              - user_info
            # 应用的provider,注意,这个名称可以随便命名,但是必须与下面的provider保持一致
            provider: giteeprovider
        provider:
          giteeprovider:
            # gitee认证授权地址
            authorizationUri: https://gitee.com/oauth/authorize
            # gitee获取access_token地址
            tokenUri: https://gitee.com/oauth/token
            # 客户端主页地址
            userInfoUri: https://gitee.com/api/v5/user
            # 获取用户属性的值
            userNameAttribute: name

registration的配置我们就不用多说,在前面系列2中,我们通过授权码模式方式的需要的内容和几个请求地址就是这些

  • provider是 配置授权服务器(Authorization Server)的授权地址和获取token地址,这个在:https://gitee.com/api/v5/oauth_doc#/list-item-2 (gitee官方文档可以看到它开放的端口)
  • userInfoUri:是gitee的资源服务器(Resource Server)获取用户信息的API,这个在:https://gitee.com/api/v5/swagger#/getV5User (gitee官方API文档可以看到)

3)在config包下,新增SecurityConfig

@Configuration
public class SecurityConfig {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception{
        // 所有访问必须认证
        http.authorizeHttpRequests(auth->auth.anyRequest().authenticated());
        // 默认采用oauth2Login登录
        http.oauth2Login(Customizer.withDefaults());
        return http.build();
    }
}

4)在controller包下,新建OAuth2LoginController,用于测试访问

@RestController
public class OAuth2LoginController {

    // http://localhost:8080/oauthlogin
    @GetMapping("/oauthlogin")
    public String oauthlogin(@RegisteredOAuth2AuthorizedClient OAuth2AuthorizedClient authorizedClient,
                             @AuthenticationPrincipal OAuth2User oauth2User) {
        // 这里我们取出用户名,并返回
        return oauth2User.getName();
    }
}

5)创建启动类Oauth2Lesson01Application

/**
 * 使用oauth2集成gitee的统一认证
 */
@SpringBootApplication
public class Oauth2Lesson01Application {

    public static void main(String[] args) {
        SpringApplication.run(Oauth2Lesson01Application.class, args);
    }

}

6)测试,使用浏览器访问: http://localhost:8080/oauthlogin

你会跳转到gitee的登录界面(如果你已经登陆过gitee的话,则不会跳转到该页面)
在这里插入图片描述

登录之后,你会跳转到授权页面

在这里插入图片描述

点击授权后,你就可以方法我们的自己服务/oauthlogin接口返回的用户名数据
在这里插入图片描述

结语:到这里,我们已经通过Spring Security 6的oauth2-client完成了我们在系列2中手动实现的授权码模式获得用户信息的流程。下面我们将会从源代码的方式解析oauth2-client是如何完成这一过程。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

linmoo2006

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值