Spring授权服务器:如何使用托管在单独应用程序上的登录表单?

2023-11-24

我正在使用 Spring Security 和 Spring Authorization Server 并尝试创建身份验证服务器。

我有一个基本流程,允许我使用预先构建的登录页面(从拜尔东指南- 这是我正在处理的代码)。我假设这个登录页面表单来自formLogin()像这样:

        http.authorizeRequests(authorizeRequests ->
                authorizeRequests.anyRequest().authenticated()
        )
        //.formLogin(withDefaults());
        return http.build();

login page

我想not使用此预构建的表单,因为我需要完全单独托管和运行登录表单前端应用程序。即在不同的服务器、域和代码库上。

提出这个问题的另一种方式可能是:

  • 如何禁用内置表单authorization-server所以我可以将它与完全独立的表单一起使用?
  • 有没有推荐的方法来了解如何定制我的SecurityFilterChain沿着这些思路?这是正确的查看位置吗?我发现 baledung 文章(以及类似的文章)作为起点很有帮助,但很少适用于更实际的用例。我相信 Spring Security 和 oauth2 库将允许我做我想做的事情,但并不完全清楚。

在与您讨论后,我发现您要做的实际上是对通过另一个(单独托管的)登录页面(实际上是一个单独的系统)进行身份验证的用户进行预身份验证。这个想法是另一个系统将重定向回来签署智威汤逊在查询参数中。

到那时,这实际上更像是一个联合登录问题,这正是 SAML 2.0 和 OAuth 2.0 旨在解决的问题。但是,如果您必须坚持使用签名 JWT(类似于 SAML 断言)之类的东西,我们可以建模一个相当简单的预身份验证authorization_code使用 Spring 授权服务器的流程。

Note:我还没有探索过以下选项OAuth 2.0 客户端身份验证和授权授予的 JWT 配置文件但这可能是一个可行的替代方案。看这个问题(#59).

附加说明:下面概述的方法涉及许多安全考虑因素。以下是该方法的草图。其他注意事项包括 CSRF 保护、使用表单后响应模式(类似于 SAML 2.0)来保护访问令牌而不是查询参数、主动使访问令牌过期(2 分钟或更短)等。换句话说,在可能的情况下,始终建议使用 SAML 2.0 或 OAuth 2.0 等联合登录方法,而不是此方法。

您可以从现有的开始Spring 授权服务器示例并从那里发展它。

这是重定向到外部身份验证提供程序的变体,并在重定向返回时包含预身份验证机制:

    @Bean
    @Order(1)
    public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {
        OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http);
        // @formatter:off
        http
            .exceptionHandling(exceptionHandling -> exceptionHandling
                .authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("https://some-other-sso.example/login"))
            );
        // @formatter:on
        return http.build();
    }

    @Bean
    @Order(2)
    public SecurityFilterChain standardSecurityFilterChain(HttpSecurity http) throws Exception {
        // @formatter:off
        http
            .authorizeRequests(authorize -> authorize
                .anyRequest().authenticated()
            )
            .oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt);
        // @formatter:on

        return http.build();
    }

    @Bean
    public JwtDecoder jwtDecoder(PublicKey publicKey) {
        return NimbusJwtDecoder.withPublicKey((RSAPublicKey) publicKey).build();
    }

    @Bean
    public BearerTokenResolver bearerTokenResolver() {
        DefaultBearerTokenResolver bearerTokenResolver = new DefaultBearerTokenResolver();
        bearerTokenResolver.setAllowUriQueryParameter(true);
        return bearerTokenResolver;
    }

第一个过滤器链在授权服务器端点上运行,例如/oauth2/authorize, /oauth2/token等。请注意/oauth2/authorize端点需要经过身份验证的用户才能运行,这意味着如果调用端点,则必须对用户进行身份验证,否则将调用身份验证入口点,该入口点将重定向到外部提供者。另请注意,两方之间必须存在信任关系,因为我们没有将 OAuth 用于外部 SSO。

当来自 oauth 客户端的重定向到达/oauth2/authorize?...端点,该请求由 Spring Security 缓存,以便稍后重播(请参阅下面的控制器)。

第二个过滤器链使用签名的 JWT 对用户进行身份验证。它还包括一个定制的BearerTokenResolver它从 URL 中的查询参数读取 JWT (?access_token=...).

The PublicKey注入到JwtDecoder将来自外部 SSO 提供商,因此您可以将其插入,但它对您的设置有意义。

我们可以创建一个存根身份验证端点,将签名的 JWT 转换为授权服务器上经过身份验证的会话,如下所示:

@Controller
public class SsoController {
    private AuthenticationSuccessHandler successHandler = new SavedRequestAwareAuthenticationSuccessHandler();

    @GetMapping("/login")
    public void login(HttpServletRequest request, HttpServletResponse response, Authentication authentication)
            throws ServletException, IOException {
        this.successHandler.onAuthenticationSuccess(request, response, authentication);
    }
}

The .oauth2ResourceServer()DSL 使用户在以下情况下进行身份验证:/login端点被调用。它需要一个access_token参数(由BearerTokenResolver)通过验证签名的 JWT 作为用户已通过外部身份验证的断言来对用户进行预身份验证。此时,将创建一个会话,该会话将验证该浏览器将来的所有请求。

然后调用控制器,并使用以下命令简单地重定向回真正的授权端点SavedRequestAwareAuthenticationSuccessHandler,这将愉快地启动authorization_code flow.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Spring授权服务器:如何使用托管在单独应用程序上的登录表单? 的相关文章

随机推荐

  • iOS:让应用程序像服务一样运行

    在 iOS 中 我如何指示操作系统让我的应用程序保持运行 即使它不再位于前台 Skype Viber Empatica Zenly 还有更多的应用程序可以做到这一点 基本上 iOS 中不存在服务类型应用程序或功能之类的东西 即使是 后台 应
  • 从“int”转换为“size_t”可能会改变结果的符号 - GCC,C

    在我的项目中 我打开了将警告视为错误并使用 pedantic and ansi标签 我正在使用 GCC 编译器 在这个项目中 我必须使用第三方源代码 该源代码有很多警告 由于我将警告视为错误 因此我在修复他们的代码时遇到了困难 大多数警告都
  • 如何在 IE7 中垂直对齐文本而不使用 CSS 'table-cell' 属性?

    我有固定高度的 div 其中包含文本 我希望文本在 div 中间垂直对齐 但问题在于某些文本是单行 而有些文本则分成两行 对于 IE8 Chrome 和 Firefox 使用display table cell and vertical a
  • 在函数中创建类并访问在包含函数的作用域中定义的函数[重复]

    这个问题在这里已经有答案了 Edit 请参阅我在这个问题底部的完整答案 tl 博士回答 Python 具有静态嵌套作用域 这static方面可以与隐式变量声明交互 产生不明显的结果 这可能特别令人惊讶 因为该语言通常是动态的 我以为我对 P
  • Python:midi 到音频流

    我需要将 MIDI 数据转换 合成为音频流 PCM 数据 有什么简单的方法可以做到这一点 随你挑选关于你想要做什么 页面上有一个 MIDI 部分
  • 在matplotlib中计算白色背景上alpha为0.5的RGB等效值

    我希望能够在 matplotlib 中以 0 5 的 alpha 值在白色背景上复制原色 r g 或 b 的外观 同时将 alpha 值保持为 1 下面是一个示例 通过手动实验 我发现 alpha 为 1 的 RGB 值看起来与 alpha
  • 当没有返回结果时处理 ExecuteScalar()

    我正在使用以下 SQL 查询和ExecuteScalar 从Oracle数据库获取数据的方法 sql select username from usermst where userid 2 string getusername comman
  • 重置用户密码

    我正在尝试找到一种通过非交互式登录在 Azure Active Directory 中重置用户密码 所有用户 而不仅仅是经过身份验证的用户 的解决方案 目前看来这只能通过 powershell 的 MSOnline 获得Set AzureA
  • Android 模拟器替代品

    我对 Android 开发完全陌生 但我刚刚拥有一台 HTC Hero 想为其开发一些应用程序 然而 我使用笔记本电脑作为我的开发机器 并且模拟器非常慢 启动大约需要 10 15 分钟 虽然我可以让它保持打开状态 但在使用其他应用程序 如
  • LINQ 按空列排序,其中顺序为升序,空值应该在最后

    我正在尝试按价格对产品列表进行排序 结果集需要按列按价格从低到高列出产品LowestPrice 但是 该列可以为空 我可以按降序对列表进行排序 如下所示 var products from p in context Products whe
  • 如何从Application.Path获取UNC路径?

    我想获取 vba 代码中活动工作簿的路径 ActiveWorkbook Path做这个 BUT 我需要它来检索这样的东西 MachineName ShareFolder ETC ETC2 NOT S ETC ETC2 Where S 映射到
  • 为什么在访问模型时,backbone.js 返回一个空数组?

    我有一个路由器访问其集合 我的 for 循环没有迭代模型 因此我尝试记录集合以查看它返回的内容 事实证明 当我直接记录集合时 我会按预期看到所有模型 但是 如果我尝试记录集合的 models 属性 我会得到一个空数组 这没有道理 这些线直接
  • C# 中 async/await 的这种用法以前被发现过吗? [关闭]

    很难说出这里问的是什么 这个问题模棱两可 含糊不清 不完整 过于宽泛或言辞激烈 无法以目前的形式合理回答 如需帮助澄清此问题以便重新打开 访问帮助中心 在我之前在 stackoverflow 上提出了关于 async await 的问题之后
  • 以编程方式查明进程是否需要用户输入

    我如何以编程方式 在 C 中 确定另一个外部应用程序 本机 java NET 或其他 当前是否需要用户输入 这可以在托管代码中完全完成吗 我正在寻找的是实施 static Boolean IsWaitingForUserInput Stri
  • Google Maps API 自动完成同一页面上的第二个地址字段

    我在我的页面上使用 Google Maps API 该页面要求用户填写您的 当前地址 和 新地址 我可以让自动完成功能在第一个地址上工作 但它不适用于第二个地址 我做了很多研究并查看了 stackoverflow 上的类似帖子 但我找不到任
  • 在 try/catch 块中等待两个承诺会导致“未处理的承诺拒绝”[重复]

    这个问题在这里已经有答案了 我想等待两个并行运行的承诺 我不想连续等待每个承诺 这有效但速度较慢 出于这个原因 我认为我可以首先创建两个承诺来让它们滚动 比如说两个网络请求 然后等待它们并能够在 catch 块中捕获错误 这个假设似乎是不正
  • Django - 按模板中的某个字段对查询集进行分组

    我有一张桌子Events 按字段排序date 我想打印模板中的事件 但为每个日期使用单独的 div 例如 div class content h1 December 30th h1 div div class content h1 Dece
  • #1025 - mysql 中重命名错误(errno:150)

    我试图在一个表 misc 中删除一个外键 id 它是表 main 中的主键 id 数据库名称 xxx alter table misc drop FOREIGN KEY id 我收到这个错误 1025 将 interview sql edc
  • 如何使用 dotnet CLI 构建 .NET Framework 4.8 应用程序?

    我继承了一个 NET Framework 4 8 应用程序 我可以使用 Visual Studio 对其进行编译 但是当尝试使用dotnetCLI 应用程序 对于我从外部依赖项使用的所有类型 我都会收到 CS0246 错误 原来的错误消息
  • Spring授权服务器:如何使用托管在单独应用程序上的登录表单?

    我正在使用 Spring Security 和 Spring Authorization Server 并尝试创建身份验证服务器 我有一个基本流程 允许我使用预先构建的登录页面 从拜尔东指南 这是我正在处理的代码 我假设这个登录页面表单来自