当前位置: 首页 > news >正文

使用 Spring Security 实现 OAuth2:一步一步的操作指南

前言

OAuth 是一种授权框架,用于创建权限策略,并允许应用程序对用户在 HTTP 服务(如 GitHub 和 Google)上的账户进行有限访问。它的工作原理是允许用户授权第三方应用访问他们的数据,而无需分享他们的凭证。本文将指导你如何在Spring Boot应用中使用 Spring Security 实现 OAuth2,并通过 OAuth2 提供商启用安全的登录和用户数据访问。

简而言之,这篇文章的内容是讲解如何在 Spring Boot 项目中集成 OAuth2,使得用户可以通过 OAuth2 提供商(比如 Google 或 github)进行安全登录,而不需要直接暴露密码等敏感信息。

什么是OAuth2?

OAuth2(开放授权 2.0)是一个授权框架,允许应用程序在不暴露用户凭证的情况下,获得对 GitHub 或 Google 等 HTTP 服务上用户账户的有限访问权限。OAuth2 为用户提供了一种方法,使他们能够在不与第三方应用共享密码的情况下访问自己的资源。

简单来说,OAuth2 允许用户授权第三方应用访问他们在其他平台上的数据,但同时避免了密码泄露的风险,确保了用户的账户安全。

关键组件

  • Resource Owner (资源所有者):是授权应用访问其账户的用户。
  • Client (客户端):是请求访问用户账户的应用程序。
  • Authorization Server (授权服务器):是验证用户身份并向客户端颁发访问令牌的服务器。
  • Resource Server (资源服务器):是托管受保护资源并接受访问令牌以允许应用访问这些资源的服务器。

OAuth2 授权流程

OAuth2 定义了几种授权流程,以适应不同的使用场景:

1、Authorization Code Grant (授权码授权):

  • 适用于服务器端应用程序。此流程涉及应用程序用授权码交换访问令牌。

  • 这是最常见的 OAuth2 流程,安全性较高,适用于需要安全存储客户端密钥的应用程序。

2、Implicit Grant (简化授权):

  • 适用于客户端应用程序(例如浏览器中的单页应用)。在这种流程中,访问令牌会直接返回,而不需要进行授权码交换。
  • 该流程较为简单,但安全性较低,因为令牌直接暴露给客户端。

3、Resource Owner Password Credentials Grant (资源所有者密码凭证授权):

  • 适用于信任客户端的应用程序,在这种情况下,客户端可以直接请求资源所有者的凭证(用户名和密码)。
  • 该流程不推荐用于不受信任的应用,因为它需要用户直接向客户端提供凭证。

4、Client Credentials Grant (客户端凭证授权):

  • 适用于客户端需要访问自己的资源,而不是资源所有者的资源的情况。
  • 该流程不涉及用户交互,通常用于机器对机器的授权场景,例如后台服务的认证。

先决条件

  • 1、对 Spring Boot 和 Spring Security 有良好的了解;
  • 2、在本地系统中安装 JDK 和 IntelliJ IDEA
  • 3、Google Console 帐户作为 OAuth2 提供者 或者github
  • 4、使用 Maven 进行依赖管理和构建

实现 OAuth2 与 Spring Security 集成

步骤1:创建一个新的Spring Boot项目

使用IntelliJ Idea创建一个新的Spring Boot项目,在创建项目时,选择以下选项:

  • Project Name: oauth2-spring-security
  • Language: Java
  • Type: Maven
  • Packaging: Jar
    在这里插入图片描述

步骤2:添加依赖项

将以下依赖项添加到Spring项目中。
在这里插入图片描述
创建项目后,IDE中的文件夹结构如下图所示:
在这里插入图片描述

步骤3:配置应用程序属性

打开应用程序。属性文件,并将谷歌OAuth配置代码添加到项目中。

spring.application.name=oauth2-spring-security
spring.security.oauth2.client.registration.google.client-id=xxxxxxxxxxxx-hjjujqg0rsjlocde5esmjelr7p6rl5a1.apps.googleusercontent.com
spring.security.oauth2.client.registration.google.client-secret=xxxxxxx-x-_hDO3tFTOsCatT2P7CZQDUKb4l
spring.security.oauth2.client.registration.google.redirect-uri=http://localhost:8080/login/oauth2/code/{registrationId}
spring.security.oauth2.client.registration.google.scope=profile, emailspring.security.oauth2.client.registration.github.client-id=xxxxxxxxBsTQfkTtULzE
spring.security.oauth2.client.registration.github.client-secret=xxxxxxxxxxx816d1d112f411f7f5df3da721a322c

步骤4:创建用户类

package org.example.model;import lombok.Data;@Data
public class User {private String name;private String email;// Getters and Setterspublic String getName() {return name;}public void setName(String name) {this.name = name;}public String getEmail() {return email;}public void setEmail(String email) {this.email = email;}
}

这个类用name和email属性定义User模型。它使用Lombok注释来简化样板代码。

步骤5:创建UserService类

这个服务类负责从OAuth2User数据创建User对象。

package org.example.service;import org.example.model.User;
import org.springframework.security.oauth2.core.user.OAuth2User;
import org.springframework.stereotype.Service;@Service
public class UserService {public User createUser(OAuth2User oAuth2User) {User user = new User();// Set user attributes from OAuth2Useruser.setName(oAuth2User.getAttribute("name"));user.setEmail(oAuth2User.getAttribute("email"));return user;}
}

步骤6:创建SecurityConfig类

package org.example.config;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.web.SecurityFilterChain;/*** @author Administrator*/
@Configuration
@EnableWebSecurity
public class SecurityConfig {@Beanpublic SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {http// Authorize requests.authorizeHttpRequests(authorizeRequests ->authorizeRequests.requestMatchers("/", "/login").permitAll().anyRequest().authenticated())// Configure OAuth2 login.oauth2Login(oauth2Login ->oauth2Login.loginPage("/login").defaultSuccessUrl("/home", true));return http.build();}
}

步骤8:主类

package org.example;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
public class Oauth2SpringSecurityApplication {public static void main(String[] args) {SpringApplication.run(Oauth2SpringSecurityApplication.class, args);}}

步骤9:创建登录HTML文件

<!DOCTYPE html>
<html xmlns:th="https://www.thymeleaf.org/">
<head><title>Login</title><link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css"><style>body {background-color: #f8f9fa;}.navbar {background-color: #81c784; /* Light Green */}.navbar-brand {color: white !important;}.container {margin-top: 100px;}.card {border: none;border-radius: 10px;box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);}.card-header {background-color: #81c784; /* Light Green */color: white;border-top-left-radius: 10px;border-top-right-radius: 10px;}.btn-custom {background-color: #81c784; /* Light Green */color: white;border-radius: 5px;}.btn-custom:hover {background-color: #66bb6a; /* Darker Green */color: white;}</style>
</head>
<body>
<nav class="navbar navbar-expand-lg"><a class="navbar-brand" href="#">My App</a>
</nav>
<div class="container"><div class="row justify-content-center"><div class="col-md-6"><div class="card"><div class="card-header text-center">Login with OAuth2</div><div class="card-body text-center"><p class="card-text">Please login using one of the following options:</p><a class="btn btn-custom" href="/oauth2/authorization/google">Login with Google</a></div></div></div><div class="col-md-6"><div class="card"><div class="card-header text-center">Login with OAuth2</div><div class="card-body text-center"><p class="card-text">Please login using one of the following options:</p><a class="btn btn-custom" href="/oauth2/authorization/github">Login with github</a></div></div></div></div>
</div>
<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.9.2/dist/umd/popper.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>
</body>
</html>

步骤10:创建主HTML文件

<!DOCTYPE html>
<html xmlns:th="https://www.thymeleaf.org/">
<head><title>Home</title><link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css"><style>body {background-color: #f8f9fa;}.navbar {background-color: #81c784; /* Light Green */}.navbar-brand, .nav-link {color: white !important;}.container {margin-top: 50px;}.card {border: none;border-radius: 10px;box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);}.card-header {background-color: #81c784; /* Light Green */color: white;border-top-left-radius: 10px;border-top-right-radius: 10px;}</style>
</head>
<body>
<nav class="navbar navbar-expand-lg"><a class="navbar-brand" href="#">My App</a><div class="collapse navbar-collapse"><ul class="navbar-nav ml-auto"><li class="nav-item"><a class="nav-link" href="/logout">Logout</a></li></ul></div>
</nav>
<div class="container"><div class="row justify-content-center"><div class="col-md-8"><div class="card"><div class="card-header">Welcome, <span th:text="${name}"></span>!</div><div class="card-body"><p class="card-text">You are now logged in using OAuth2.</p></div></div></div></div>
</div>
<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.9.2/dist/umd/popper.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>
</body>
</html>

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>3.5.5</version><relativePath/> <!-- lookup parent from repository --></parent><groupId>org.example</groupId><artifactId>oauth2-spring-security</artifactId><version>0.0.1-SNAPSHOT</version><name>oauth2-spring-security</name><description>oauth2-spring-security</description><url/><licenses><license/></licenses><developers><developer/></developers><scm><connection/><developerConnection/><tag/><url/></scm><properties><java.version>17</java.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-oauth2-client</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.thymeleaf.extras</groupId><artifactId>thymeleaf-extras-springsecurity6</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><scope>runtime</scope><optional>true</optional></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>org.springframework.security</groupId><artifactId>spring-security-test</artifactId><scope>test</scope></dependency></dependencies><build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><configuration><annotationProcessorPaths><path><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></path></annotationProcessorPaths></configuration></plugin><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><configuration><excludes><exclude><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></exclude></excludes></configuration></plugin></plugins></build></project>

步骤11:运行应用程序

D:\Java\corretto-17.0.5\bin\java.exe -XX:TieredStopAtLevel=1 -Dspring.output.ansi.enabled=always -Dcom.sun.management.jmxremote -Dspring.jmx.enabled=true -Dspring.liveBeansView.mbeanDomain -Dspring.application.admin.enabled=true "-Dmanagement.endpoints.jmx.exposure.include=*" "-javaagent:D:\JetBrains\IntelliJ IDEA 2024.1.4\lib\idea_rt.jar=4012:D:\JetBrains\IntelliJ IDEA 2024.1.4\bin" -Dfile.encoding=UTF-8 -classpath D:\02\oauth2-spring-security\target\classes;C:\Users\Administrator\.m2\repository\org\springframework\boot\spring-boot-starter-oauth2-client\3.5.5\spring-boot-starter-oauth2-client-3.5.5.jar;C:\Users\Administrator\.m2\repository\org\springframework\boot\spring-boot-starter\3.5.5\spring-boot-starter-3.5.5.jar;C:\Users\Administrator\.m2\repository\org\springframework\boot\spring-boot-starter-logging\3.5.5\spring-boot-starter-logging-3.5.5.jar;C:\Users\Administrator\.m2\repository\ch\qos\logback\logback-classic\1.5.18\logback-classic-1.5.18.jar;C:\Users\Administrator\.m2\repository\ch\qos\logback\logback-core\1.5.18\logback-core-1.5.18.jar;C:\Users\Administrator\.m2\repository\org\apache\logging\log4j\log4j-to-slf4j\2.24.3\log4j-to-slf4j-2.24.3.jar;C:\Users\Administrator\.m2\repository\org\apache\logging\log4j\log4j-api\2.24.3\log4j-api-2.24.3.jar;C:\Users\Administrator\.m2\repository\org\slf4j\jul-to-slf4j\2.0.17\jul-to-slf4j-2.0.17.jar;C:\Users\Administrator\.m2\repository\jakarta\annotation\jakarta.annotation-api\2.1.1\jakarta.annotation-api-2.1.1.jar;C:\Users\Administrator\.m2\repository\org\yaml\snakeyaml\2.4\snakeyaml-2.4.jar;C:\Users\Administrator\.m2\repository\org\springframework\security\spring-security-config\6.5.3\spring-security-config-6.5.3.jar;C:\Users\Administrator\.m2\repository\org\springframework\spring-beans\6.2.10\spring-beans-6.2.10.jar;C:\Users\Administrator\.m2\repository\org\springframework\spring-context\6.2.10\spring-context-6.2.10.jar;C:\Users\Administrator\.m2\repository\org\springframework\security\spring-security-core\6.5.3\spring-security-core-6.5.3.jar;C:\Users\Administrator\.m2\repository\org\springframework\security\spring-security-crypto\6.5.3\spring-security-crypto-6.5.3.jar;C:\Users\Administrator\.m2\repository\org\springframework\spring-expression\6.2.10\spring-expression-6.2.10.jar;C:\Users\Administrator\.m2\repository\io\micrometer\micrometer-observation\1.15.3\micrometer-observation-1.15.3.jar;C:\Users\Administrator\.m2\repository\io\micrometer\micrometer-commons\1.15.3\micrometer-commons-1.15.3.jar;C:\Users\Administrator\.m2\repository\org\springframework\security\spring-security-oauth2-client\6.5.3\spring-security-oauth2-client-6.5.3.jar;C:\Users\Administrator\.m2\repository\org\springframework\security\spring-security-oauth2-core\6.5.3\spring-security-oauth2-core-6.5.3.jar;C:\Users\Administrator\.m2\repository\com\nimbusds\oauth2-oidc-sdk\9.43.6\oauth2-oidc-sdk-9.43.6.jar;C:\Users\Administrator\.m2\repository\com\github\stephenc\jcip\jcip-annotations\1.0-1\jcip-annotations-1.0-1.jar;C:\Users\Administrator\.m2\repository\com\nimbusds\content-type\2.2\content-type-2.2.jar;C:\Users\Administrator\.m2\repository\com\nimbusds\lang-tag\1.7\lang-tag-1.7.jar;C:\Users\Administrator\.m2\repository\org\springframework\security\spring-security-oauth2-jose\6.5.3\spring-security-oauth2-jose-6.5.3.jar;C:\Users\Administrator\.m2\repository\com\nimbusds\nimbus-jose-jwt\9.37.3\nimbus-jose-jwt-9.37.3.jar;C:\Users\Administrator\.m2\repository\org\springframework\boot\spring-boot-starter-security\3.5.5\spring-boot-starter-security-3.5.5.jar;C:\Users\Administrator\.m2\repository\org\springframework\spring-aop\6.2.10\spring-aop-6.2.10.jar;C:\Users\Administrator\.m2\repository\org\springframework\security\spring-security-web\6.5.3\spring-security-web-6.5.3.jar;C:\Users\Administrator\.m2\repository\org\springframework\boot\spring-boot-starter-thymeleaf\3.5.5\spring-boot-starter-thymeleaf-3.5.5.jar;C:\Users\Administrator\.m2\repository\org\thymeleaf\thymeleaf-spring6\3.1.3.RELEASE\thymeleaf-spring6-3.1.3.RELEASE.jar;C:\Users\Administrator\.m2\repository\org\thymeleaf\thymeleaf\3.1.3.RELEASE\thymeleaf-3.1.3.RELEASE.jar;C:\Users\Administrator\.m2\repository\org\attoparser\attoparser\2.0.7.RELEASE\attoparser-2.0.7.RELEASE.jar;C:\Users\Administrator\.m2\repository\org\unbescape\unbescape\1.1.6.RELEASE\unbescape-1.1.6.RELEASE.jar;C:\Users\Administrator\.m2\repository\org\springframework\boot\spring-boot-starter-web\3.5.5\spring-boot-starter-web-3.5.5.jar;C:\Users\Administrator\.m2\repository\org\springframework\boot\spring-boot-starter-json\3.5.5\spring-boot-starter-json-3.5.5.jar;C:\Users\Administrator\.m2\repository\com\fasterxml\jackson\core\jackson-databind\2.19.2\jackson-databind-2.19.2.jar;C:\Users\Administrator\.m2\repository\com\fasterxml\jackson\core\jackson-annotations\2.19.2\jackson-annotations-2.19.2.jar;C:\Users\Administrator\.m2\repository\com\fasterxml\jackson\core\jackson-core\2.19.2\jackson-core-2.19.2.jar;C:\Users\Administrator\.m2\repository\com\fasterxml\jackson\datatype\jackson-datatype-jdk8\2.19.2\jackson-datatype-jdk8-2.19.2.jar;C:\Users\Administrator\.m2\repository\com\fasterxml\jackson\datatype\jackson-datatype-jsr310\2.19.2\jackson-datatype-jsr310-2.19.2.jar;C:\Users\Administrator\.m2\repository\com\fasterxml\jackson\module\jackson-module-parameter-names\2.19.2\jackson-module-parameter-names-2.19.2.jar;C:\Users\Administrator\.m2\repository\org\springframework\boot\spring-boot-starter-tomcat\3.5.5\spring-boot-starter-tomcat-3.5.5.jar;C:\Users\Administrator\.m2\repository\org\apache\tomcat\embed\tomcat-embed-core\10.1.44\tomcat-embed-core-10.1.44.jar;C:\Users\Administrator\.m2\repository\org\apache\tomcat\embed\tomcat-embed-el\10.1.44\tomcat-embed-el-10.1.44.jar;C:\Users\Administrator\.m2\repository\org\apache\tomcat\embed\tomcat-embed-websocket\10.1.44\tomcat-embed-websocket-10.1.44.jar;C:\Users\Administrator\.m2\repository\org\springframework\spring-web\6.2.10\spring-web-6.2.10.jar;C:\Users\Administrator\.m2\repository\org\springframework\spring-webmvc\6.2.10\spring-webmvc-6.2.10.jar;C:\Users\Administrator\.m2\repository\org\thymeleaf\extras\thymeleaf-extras-springsecurity6\3.1.3.RELEASE\thymeleaf-extras-springsecurity6-3.1.3.RELEASE.jar;C:\Users\Administrator\.m2\repository\org\slf4j\slf4j-api\2.0.17\slf4j-api-2.0.17.jar;C:\Users\Administrator\.m2\repository\org\springframework\boot\spring-boot-devtools\3.5.5\spring-boot-devtools-3.5.5.jar;C:\Users\Administrator\.m2\repository\org\springframework\boot\spring-boot\3.5.5\spring-boot-3.5.5.jar;C:\Users\Administrator\.m2\repository\org\springframework\boot\spring-boot-autoconfigure\3.5.5\spring-boot-autoconfigure-3.5.5.jar;C:\Users\Administrator\.m2\repository\org\projectlombok\lombok\1.18.38\lombok-1.18.38.jar;C:\Users\Administrator\.m2\repository\net\minidev\json-smart\2.5.2\json-smart-2.5.2.jar;C:\Users\Administrator\.m2\repository\net\minidev\accessors-smart\2.5.2\accessors-smart-2.5.2.jar;C:\Users\Administrator\.m2\repository\org\ow2\asm\asm\9.7.1\asm-9.7.1.jar;C:\Users\Administrator\.m2\repository\org\springframework\spring-core\6.2.10\spring-core-6.2.10.jar;C:\Users\Administrator\.m2\repository\org\springframework\spring-jcl\6.2.10\spring-jcl-6.2.10.jar org.example.Oauth2SpringSecurityApplication.   ____          _            __ _ _/\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \\\/  ___)| |_)| | | | | || (_| |  ) ) ) )'  |____| .__|_| |_|_| |_\__, | / / / /=========|_|==============|___/=/_/_/_/:: Spring Boot ::                (v3.5.5)2025-09-07T21:35:35.024+08:00  INFO 3272 --- [oauth2-spring-security] [  restartedMain] o.e.Oauth2SpringSecurityApplication      : Starting Oauth2SpringSecurityApplication using Java 17.0.5 with PID 3272 (D:\02\oauth2-spring-security\target\classes started by Administrator in D:\02\oauth2-spring-security)
2025-09-07T21:35:35.036+08:00  INFO 3272 --- [oauth2-spring-security] [  restartedMain] o.e.Oauth2SpringSecurityApplication      : No active profile set, falling back to 1 default profile: "default"
2025-09-07T21:35:35.200+08:00  INFO 3272 --- [oauth2-spring-security] [  restartedMain] .e.DevToolsPropertyDefaultsPostProcessor : Devtools property defaults active! Set 'spring.devtools.add-properties' to 'false' to disable
2025-09-07T21:35:35.200+08:00  INFO 3272 --- [oauth2-spring-security] [  restartedMain] .e.DevToolsPropertyDefaultsPostProcessor : For additional web related logging consider setting the 'logging.level.web' property to 'DEBUG'
2025-09-07T21:35:37.926+08:00  INFO 3272 --- [oauth2-spring-security] [  restartedMain] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port 8080 (http)
2025-09-07T21:35:37.963+08:00  INFO 3272 --- [oauth2-spring-security] [  restartedMain] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2025-09-07T21:35:37.963+08:00  INFO 3272 --- [oauth2-spring-security] [  restartedMain] o.apache.catalina.core.StandardEngine    : Starting Servlet engine: [Apache Tomcat/10.1.44]
2025-09-07T21:35:38.074+08:00  INFO 3272 --- [oauth2-spring-security] [  restartedMain] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2025-09-07T21:35:38.074+08:00  INFO 3272 --- [oauth2-spring-security] [  restartedMain] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 2872 ms
2025-09-07T21:35:39.463+08:00  INFO 3272 --- [oauth2-spring-security] [  restartedMain] o.s.b.d.a.OptionalLiveReloadServer       : LiveReload server is running on port 35729
2025-09-07T21:35:39.540+08:00  INFO 3272 --- [oauth2-spring-security] [  restartedMain] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port 8080 (http) with context path '/'
2025-09-07T21:35:39.562+08:00  INFO 3272 --- [oauth2-spring-security] [  restartedMain] o.e.Oauth2SpringSecurityApplication      : Started Oauth2SpringSecurityApplication in 5.87 seconds (process running for 9.315)

步骤12:测试应用程序

登录页http://localhost:8080/login
在这里插入图片描述
Google OAuth Authentication:
在这里插入图片描述
在这里插入图片描述
首页 http://localhost:8080/home
在这里插入图片描述
github OAuth Authentication:

在这里插入图片描述


文章转载自:

http://lADwYpbh.qncmn.cn
http://U5EY6FqG.qncmn.cn
http://sgdBN7fQ.qncmn.cn
http://9gI7XBEg.qncmn.cn
http://QsPVNjyX.qncmn.cn
http://O4pGs1Pq.qncmn.cn
http://1iogOSYa.qncmn.cn
http://ErROGyQZ.qncmn.cn
http://riT8FVF6.qncmn.cn
http://8GLPr24C.qncmn.cn
http://UG12lAet.qncmn.cn
http://TXRwVLty.qncmn.cn
http://sNmNyX57.qncmn.cn
http://IQWA0uyJ.qncmn.cn
http://wUINq286.qncmn.cn
http://osrADhh8.qncmn.cn
http://Bakz5YRQ.qncmn.cn
http://Ynql5aJP.qncmn.cn
http://qN1GwypQ.qncmn.cn
http://10We3BCl.qncmn.cn
http://nrzWEfOj.qncmn.cn
http://vWWK0S7p.qncmn.cn
http://Mm9RNDYW.qncmn.cn
http://DS9NrDOU.qncmn.cn
http://syRFgAhs.qncmn.cn
http://WDYd5epI.qncmn.cn
http://8duCPxOD.qncmn.cn
http://VhcmYUIO.qncmn.cn
http://TsFStvXi.qncmn.cn
http://FSrUGDbo.qncmn.cn
http://www.dtcms.com/a/372156.html

相关文章:

  • Axure: 分组柱状图1
  • CEEMDAN-PSO-CNN-GRU 锂电池健康状态预测matlab
  • Spring Cloud Gateway 作为一个独立的服务进行部署吗
  • webrtc弱网-LossBasedBweV2类源码分析与算法原理
  • leetcode hot100 二叉搜索树
  • 杂学项目1、S32K144与上位机通信
  • GitHub自动化利器:Probot框架实战指南
  • 一款没有任何限制的免费远程手机控制手机的软件简介
  • 企云网多应用授权系统源码 正版查询系统源码
  • Windows netstat 命令使用说明
  • 软件工程:DO-178中的适航要求核心要素
  • Caffeine Count-Min Sketch TinyLFU实现:FrequencySketch
  • 【系统分析师】第7章-基础知识:软件工程(核心总结)
  • 【拍摄学习记录】00-总结记录
  • 探索 CSS 过渡:打造流畅网页交互体验
  • 大语言模型(LLM)的基本概念
  • unsloth FastLanguageModel类主要函数详解,具体作用和参数
  • HTTPS协议——对于HTTP的协议的加密
  • Qwen2.5-VL翻译
  • 碳纤维和短切碳纤维(中)
  • unsloth 笔记: training的时候进行evaluation
  • 【linux kernel 常用数据结构和设计模式】【数据结构 1】【如何表达数据之间的一对一、一对多、多对多关系】
  • 【软件架构设计(19)】软件架构评估二:软件架构分析方法分类、质量属性场景、软件评估方法发展历程
  • 在OpenHarmony上适配图形显示【1】——确认drm是否正常
  • 四大金刚之计算机组成原理
  • 第 15 篇:PCA与降维——如何在信息爆炸的时代,抓住“主要矛盾”?
  • 《沈南鹏传 - 做最擅长的事》(中篇)读书笔记
  • 还在重启应用改 Topic?Spring Boot 动态 Kafka 消费的“终极形态”
  • 纸飞机飞行漂流瓶小游戏抖音快手微信小程序看广告流量主开源
  • 《沈南鹏传 - 做最擅长的事》(下篇)读书笔记