使用 Twitch 进行身份验证时的 Spring-Boot OAuth2 奇怪行为

Posted

技术标签:

【中文标题】使用 Twitch 进行身份验证时的 Spring-Boot OAuth2 奇怪行为【英文标题】:Spring-Boot OAuth2 Strange Behavior When Authenticating with Twitch 【发布时间】:2022-01-05 09:46:25 【问题描述】:

几天来,我一直在尝试通过 Spring 使用 Twitch 设置 OAuth2。在这个过程中我已经解决了很多问题,但这个问题让我很难过。当我尝试访问我试图要求用户通过 Twitch 进行身份验证的端点之一时,我被重定向到 localhost:8080/login 并显示一个页面,该页面仅显示“使用 OAuth 2.0 登录”并且没有其他内容在上面。我的期望是 Spring 会自动将我重定向到 Twitch 的身份验证门户,然后 Twitch 会在完成 OAuth 流程后将我发送回 Spring 应用程序。相反,我只是被显示该页面而没有发生任何事情。

就目前为止为解决这个问题所做的工作......几乎没有。我找不到其他人遇到这个问题,所以我认为可能存在一些问题...根据本教程https://spring.io/guides/tutorials/spring-boot-oauth2/,Spring 似乎具有许多不同 OAuth 的开箱即用功能提供者。我猜Twitch不是其中之一。这让我担心 Twitch 后端的某些东西可能会导致 Spring 出现这个问题(如果是这种情况,那么我将需要制作一个自定义身份验证器)。我想到的另一种可能性是,可能需要告诉 Spring 将用户重定向到哪里,以便他们获得身份验证。如果是这种情况,那么我将不胜感激,因为我无法找到任何迹象表明这是需要在线完成的事情(而且我不知道该怎么做)。

我项目中的一些重要文件:

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>2.5.7</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.redacted</groupId>
    <artifactId>redacted</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>redacted</name>
    <description>redacted</description>
    <properties>
        <java.version>17</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-jasper</artifactId>
            <version>9.0.44</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
            <version>2.4.4</version>
            <scope>provided</scope>
        </dependency>
        <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>javax.servlet</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
        </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>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-rest</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <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>

application.properties:

spring.mvc.view.prefix=/WEB-INF/jsp/
spring.mvc.view.suffix=.jsp

spring.security.oauth2.client.registration.twitch.client-id=redacted
spring.security.oauth2.client.registration.twitch.client-secret=redacted
spring.security.oauth2.client.registration.twitch.client-authentication-method=post
spring.security.oauth2.client.registration.twitch.redirect-uri=http://localhost:8080/login/oauth2/code/twitch
spring.security.oauth2.client.registration.twitch.provider=twitch
spring.security.oauth2.client.registration.twitch.scope=user:read:email
spring.security.oauth2.client.registration.twitch.authorization-grant-type=AUTHORIZATION_CODE

spring.security.oauth2.client.provider.twitch.authorization-uri=https://id.twitch.tv/oauth2/authorize
spring.security.oauth2.client.provider.twitch.token-uri=https://id.twitch.tv/oauth2/token
spring.security.oauth2.client.provider.twitch.user-info-uri=https://id.twitch.tv/oauth2/userinfo
spring.security.oauth2.client.provider.twitch.user-name-attribute=redacted

还有我的 SpringSecurityConfiguration 文件,以防万一:

package com.redacted;

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.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@Configuration
@EnableWebSecurity
public class SpringSecurityConfiguration extends WebSecurityConfigurerAdapter 

    @Override
    public void configure(HttpSecurity httpSecurity) throws Exception 
        //This allows users to access the "/" and "/Info" endpoints without authenticating with Twitch. To go anywhere else they will have to authenticate.
        httpSecurity.antMatcher("/**").authorizeRequests().antMatchers("/", "/Info").permitAll().anyRequest().authenticated().and().oauth2Login();
    

我的项目结构:

感谢您的时间和考虑,感谢您的帮助。

-时代

编辑:

我最近发现一些我认为可以谨慎添加到此讨论中的内容 - 当我尝试在当前设置中访问安全页面时,我看到此屏幕:

看起来 Spring 通常显示此屏幕的预期方式是这样的:

就好像 Spring 根本没有看到我的 Oauth 提供者一样。不确定这些信息是否有帮助,但我想我会包括在内。 Springs 对 Oauth 的预期行为是,当仅配置一个提供程序时,/login 页面将被完全跳过。我实际上更希望展示这种行为(但鉴于它没有看到提供者,我认为它会显示页面)。

【问题讨论】:

查看参考文档中的property mappings。您可能希望在provider 端尽可能多地指定这些属性。您可以启用跟踪日志记录 (logging.level.org.springframework.security=trace) 并在您访问安全页面时提供输出内容吗? 我尽可能多地添加了这些,但问题仍然存在(我唯一缺少的是 issuer-uri,看起来 Twitch 没有提供其中之一)。在尝试访问安全页面后,我包含了堆栈跟踪的 pastebin:pastebin.com/yR9eRXKg 【参考方案1】:

我能够重现该问题。您已指定:

spring.security.oauth2.client.registration.twitch.authorization-grant-type=AUTHORIZATION_CODE

虽然应该是:

spring.security.oauth2.client.registration.twitch.authorization-grant-type=authorization_code

Spring Boot 无法正确加载你的配置属性,所以就好像你配置了 0 个客户端注册一样。

【讨论】:

这解决了问题。在 Reddit 上向我推荐了此问题的另一种解决方案供感兴趣的人使用:reddit.com/r/SpringBoot/comments/r5e0k6/comment/hmnx0yb/… 谢谢您的帮助! 很高兴它有帮助!是的,你也可以注册一个 bean。确保read about it in the docs,因为根据您的应用程序,有很多方法可以做事。【参考方案2】:

尝试在您的configure 方法中添加.oauth2Client() 而不是.oauth2Login()

【讨论】:

将其更改为 oauth2Client() 会导致服务器返回 403(禁止访问)错误。似乎仍然没有重定向到 Twitch 的 oauth 门户。 您能否通过运行--debug 来验证配置是否已加载? 我不完全确定如何根据调试信息验证配置是否已加载。我有一张我在 [DEBUG] 输出中看到的一些内容的示例图片。尽管我不确定它们是否基于调试进行配置,但看起来各种 oauth2 相关的依赖项确实正在编译。 imgur.com/TBlUdIn

以上是关于使用 Twitch 进行身份验证时的 Spring-Boot OAuth2 奇怪行为的主要内容,如果未能解决你的问题,请参考以下文章

将 Firebase 身份验证与自定义提供程序一起使用

使用 Spring Security 在 Spring 中进行 WebSocket 身份验证

使用 Grails 和 Spring Security 作为后端时的 Angular 前端身份验证

用户身份验证失败时的 Spring Security ProviderNotFoundException

twitch游戏直播(国外平台)如何绑定二次验证码_虚拟MFA?

使用 localhost 进行 facebook 身份验证 laravel 5.1 时的应用程序域