java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > SpringBoot3整合OAuth2第三方登录

Spring Boot3整合OAuth2实现第三方登录功能详细示例

作者:MenzilBiz

OAuth是一个关于授权的开放网络标准,在全世界得到广泛应用,目前的版本是2.0版,这篇文章主要介绍了Spring Boot3整合OAuth2实现第三方登录功能的相关资料,需要的朋友可以参考下

引言

在当今互联网应用中,第三方登录已成为提升用户体验的重要功能。通过集成OAuth2协议,我们可以让用户使用他们已有的社交媒体账号(如GitHub、Google、微信等)快速登录我们的应用,而无需创建新的账号。本文将详细介绍如何在Spring Boot 3应用中整合OAuth2实现第三方登录功能。

准备工作

在开始之前,请确保你已经具备以下条件:

添加依赖

首先,我们需要在项目中添加Spring Security和OAuth2客户端依赖:

<dependencies>
    <!-- Spring Security -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
    </dependency>
    
    <!-- OAuth2 Client -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-oauth2-client</artifactId>
    </dependency>
    
    <!-- Web支持 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    
    <!-- Thymeleaf (可选,用于前端展示) -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-thymeleaf</artifactId>
    </dependency>
    
    <!-- Lombok (简化代码) -->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
</dependencies>

配置OAuth2客户端

application.ymlapplication.properties中配置OAuth2客户端信息。这里以GitHub为例:

spring:
  security:
    oauth2:
      client:
        registration:
          github:
            client-id: your-github-client-id
            client-secret: your-github-client-secret
            scope: user:email,read:user
            redirect-uri: "{baseUrl}/login/oauth2/code/{registrationId}"
        provider:
          github:
            authorization-uri: https://github.com/login/oauth/authorize
            token-uri: https://github.com/login/oauth/access_token
            user-info-uri: https://api.github.com/user
            user-name-attribute: login

server:
  port: 8080
  servlet:
    context-path: /demo

注意:你需要先在GitHub开发者设置中创建OAuth应用,获取client-idclient-secret,并设置正确的回调URL。

配置安全策略

创建一个安全配置类来定义我们的安全策略:

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
            .csrf(csrf -> csrf.disable()) // 开发阶段可禁用CSRF
            .authorizeHttpRequests(auth -> auth
                .requestMatchers("/", "/login**", "/oauth2/**", "/error**").permitAll()
                .anyRequest().authenticated()
            )
            .oauth2Login(oauth2 -> oauth2
                .loginPage("/login")
                .defaultSuccessUrl("/home", true)
                .userInfoEndpoint(userInfo -> userInfo
                    .userService(customOAuth2UserService())
                )
                .successHandler(authenticationSuccessHandler())
            )
            .logout(logout -> logout
                .logoutSuccessUrl("/").permitAll()
                .deleteCookies("JSESSIONID")
                .invalidateHttpSession(true)
            );
        
        return http.build();
    }

    @Bean
    public OAuth2UserService<OAuth2UserRequest, OAuth2User> customOAuth2UserService() {
        return new CustomOAuth2UserService();
    }

    @Bean
    public AuthenticationSuccessHandler authenticationSuccessHandler() {
        return new CustomAuthenticationSuccessHandler();
    }
}

自定义OAuth2用户服务

我们需要创建一个自定义的OAuth2用户服务来处理用户信息:

@Slf4j
public class CustomOAuth2UserService extends DefaultOAuth2UserService {

    @Override
    public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException {
        OAuth2User oAuth2User = super.loadUser(userRequest);
        
        String registrationId = userRequest.getClientRegistration().getRegistrationId();
        String accessToken = userRequest.getAccessToken().getTokenValue();
        
        log.info("Registration ID: {}", registrationId);
        log.info("Access Token: {}", accessToken);
        log.info("User Attributes: {}", oAuth2User.getAttributes());
        
        // 根据不同平台处理用户信息
        Map<String, Object> attributes = new HashMap<>(oAuth2User.getAttributes());
        
        // 添加平台标识
        attributes.put("provider", registrationId);
        
        // 标准化用户信息
        if ("github".equals(registrationId)) {
            attributes.put("email", attributes.get("email") != null ? 
                attributes.get("email") : attributes.get("login") + "@users.noreply.github.com");
        }
        
        return new DefaultOAuth2User(
            Collections.singleton(new SimpleGrantedAuthority("ROLE_USER")),
            attributes,
            userRequest.getClientRegistration()
                .getProviderDetails()
                .getUserInfoEndpoint()
                .getUserNameAttributeName()
        );
    }
}

自定义认证成功处理器

创建一个认证成功处理器来处理登录成功后的逻辑:

@Slf4j
public class CustomAuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {

    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, 
                                      HttpServletResponse response,
                                      Authentication authentication) throws IOException {
        
        OAuth2User oauthUser = (OAuth2User) authentication.getPrincipal();
        String provider = (String) oauthUser.getAttribute("provider");
        
        log.info("User logged in from {}: {}", provider, oauthUser.getName());
        
        // 根据不同的登录来源处理不同逻辑
        if ("github".equals(provider)) {
            // GitHub特定处理逻辑
            handleGitHubUser(oauthUser);
        }
        
        // 设置默认跳转路径
        setDefaultTargetUrl("/home");
        super.onAuthenticationSuccess(request, response, authentication);
    }

    private void handleGitHubUser(OAuth2User oauthUser) {
        // 实现GitHub用户的特定处理逻辑
        // 例如保存用户信息到数据库等
    }
}

创建控制器

添加一些基本的控制器来处理页面请求:

@Controller
@RequiredArgsConstructor
public class MainController {

    @GetMapping("/")
    public String home() {
        return "index";
    }

    @GetMapping("/login")
    public String login(Model model) {
        model.addAttribute("providers", List.of("github")); // 可以扩展更多提供商
        return "login";
    }

    @GetMapping("/home")
    public String userHome(Principal principal, Model model) {
        if (principal instanceof OAuth2User oauthUser) {
            model.addAttribute("username", oauthUser.getAttribute("name"));
            model.addAttribute("avatar", oauthUser.getAttribute("avatar_url"));
            model.addAttribute("provider", oauthUser.getAttribute("provider"));
        } else {
            model.addAttribute("username", principal.getName());
        }
        return "home";
    }
}

创建前端页面

创建几个简单的Thymeleaf模板页面:

src/main/resources/templates/login.html:

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title>Login</title>
    <style>
        .oauth-provider {
            display: inline-block;
            margin: 10px;
            padding: 10px 20px;
            background: #f5f5f5;
            border-radius: 5px;
            text-decoration: none;
            color: #333;
        }
        .oauth-provider:hover {
            background: #e5e5e5;
        }
    </style>
</head>
<body>
    <h1>Login with OAuth2</h1>
    <div th:each="provider : ${providers}">
        <a class="oauth-provider" th:href="@{/oauth2/authorization/{provider}(provider=${provider})}" rel="external nofollow" >
            Login with <span th:text="${provider}"></span>
        </a>
    </div>
</body>
</html>

src/main/resources/templates/home.html:

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title>Home</title>
    <style>
        .user-info {
            display: flex;
            align-items: center;
            gap: 20px;
            margin-bottom: 20px;
        }
        .avatar {
            width: 80px;
            height: 80px;
            border-radius: 50%;
        }
    </style>
</head>
<body>
    <div class="user-info" th:if="${avatar}">
        <img class="avatar" th:src="${avatar}" alt="User Avatar"/>
        <div>
            <h1>Welcome, <span th:text="${username}"></span>!</h1>
            <p>Logged in via <span th:text="${provider}"></span></p>
        </div>
    </div>
    
    <div th:unless="${avatar}">
        <h1>Welcome, <span th:text="${username}"></span>!</h1>
    </div>
    
    <form th:action="@{/logout}" method="post">
        <button type="submit">Logout</button>
    </form>
</body>
</html>

测试应用

扩展功能

常见问题解决

总结

本文详细介绍了在Spring Boot 3中整合OAuth2实现第三方登录的完整流程。通过Spring Security的OAuth2客户端支持,我们可以轻松集成多种第三方登录提供商。关键点包括:

你可以在此基础上扩展更多功能,如用户信息持久化、多提供商支持、JWT集成等。希望这篇文章对你实现第三方登录功能有所帮助!

到此这篇关于Spring Boot3整合OAuth2实现第三方登录功能的文章就介绍到这了,更多相关SpringBoot3整合OAuth2第三方登录内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文