gpt4 book ai didi

spring-boot - 使用 Spring Boot 2 和 Spring Security 5 进行多因素身份验证

转载 作者:行者123 更新时间:2023-12-03 14:41:20 28 4
gpt4 key购买 nike

我想向 Angular 和 Spring 应用程序添加使用 TOTP 软 token 的多因素身份验证,同时使所有内容尽可能接近 Spring Boot Security Starter 的默认值。

token 验证在本地进行(使用 aerogear-otp-java 库),没有第三方 API 提供者。

为用户设置 token 是可行的,但通过利用 Spring Security Authentication Manager/Providers 来验证它们却不行。

TL;博士

  • 将额外的 AuthenticationProvider 集成到 Spring Boot Security Starter 配置的系统中的官方方法是什么?
  • 有哪些推荐的方法来防止重放攻击?

  • 长版

    API 有一个端点 /auth/token前端可以通过提供用户名和密码从中获取 JWT token 。响应还包括一个身份验证状态,可以是 。已认证 PRE_AUTHENTICATED_MFA_REQUIRED .

    如果用户需要 MFA,则以 PRE_AUTHENTICATED_MFA_REQUIRED 的单一授权权限颁发 token 。和 5 分钟的过期时间。这允许用户访问端点 /auth/mfa-token他们可以从他们的 Authenticator 应用程序中提供 TOTP 代码并获取完全经过身份验证的 token 以访问该站点。

    提供者和 token

    我已经创建了我的自定义 MfaAuthenticationProvider实现 AuthenticationProvider :
        @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
    // validate the OTP code
    }

    @Override
    public boolean supports(Class<?> authentication) {
    return OneTimePasswordAuthenticationToken.class.isAssignableFrom(authentication);
    }

    还有一个 OneTimePasswordAuthenticationToken扩展 AbstractAuthenticationToken保存用户名(取自签名的 JWT)和 OTP 代码。

    配置

    我有我的自定义 WebSecurityConfigurerAdapter ,我在其中添加我的自定义 AuthenticationProvider通过 http.authenticationProvider() .根据 JavaDoc,这似乎是正确的地方:

    Allows adding an additional AuthenticationProvider to be used



    我的相关部分 SecurityConfig看起来像这样。
        @Configuration
    @EnableWebSecurity
    @EnableJpaAuditing(auditorAwareRef = "appSecurityAuditorAware")
    public class SecurityConfig extends WebSecurityConfigurerAdapter {
    private final TokenProvider tokenProvider;

    public SecurityConfig(TokenProvider tokenProvider) {
    this.tokenProvider = tokenProvider;
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
    http.authenticationProvider(new MfaAuthenticationProvider());

    http.authorizeRequests()
    // Public endpoints, HTML, Assets, Error Pages and Login
    .antMatchers("/", "favicon.ico", "/asset/**", "/pages/**", "/api/auth/token").permitAll()

    // MFA auth endpoint
    .antMatchers("/api/auth/mfa-token").hasAuthority(ROLE_PRE_AUTH_MFA_REQUIRED)

    // much more config

    Controller
    AuthControllerAuthenticationManagerBuilder注入(inject)并将其拉到一起。
    @RestController
    @RequestMapping(AUTH)
    public class AuthController {
    private final TokenProvider tokenProvider;
    private final AuthenticationManagerBuilder authenticationManagerBuilder;

    public AuthController(TokenProvider tokenProvider, AuthenticationManagerBuilder authenticationManagerBuilder) {
    this.tokenProvider = tokenProvider;
    this.authenticationManagerBuilder = authenticationManagerBuilder;
    }

    @PostMapping("/mfa-token")
    public ResponseEntity<Token> mfaToken(@Valid @RequestBody OneTimePassword oneTimePassword) {
    var username = SecurityUtils.getCurrentUserLogin().orElse("");
    var authenticationToken = new OneTimePasswordAuthenticationToken(username, oneTimePassword.getCode());
    var authentication = authenticationManagerBuilder.getObject().authenticate(authenticationToken);

    // rest of class

    但是,针对 /auth/mfa-token 发布导致此错误:
    "error": "Forbidden",
    "message": "Access Denied",
    "trace": "org.springframework.security.authentication.ProviderNotFoundException: No AuthenticationProvider found for de.....OneTimePasswordAuthenticationToken

    为什么 Spring Security 不选择我的身份验证提供程序?调试 Controller 显示 DaoAuthenticationProviderAuthenticationProviderManager 中唯一的身份验证提供程序.

    如果我暴露我的 MfaAuthenticationProvider作为bean,它是唯一注册的提供者,所以我得到相反的结果:
    No AuthenticationProvider found for org.springframework.security.authentication.UsernamePasswordAuthenticationToken. 

    那么,我如何获得两者?

    我的问题

    集成额外的 AuthenticationProvider 的推荐方法是什么?进入一个 Spring Boot Security Starter 配置的系统,这样我就得到了 DaoAuthenticationProvider和我自己的定制 MfaAuthenticationProvider ?我想保留 Spring Boot Scurity Starter 的默认值并另外拥有自己的 Provider。

    防止重放攻击

    我知道 OTP 算法本身并不能在代码有效的时间片内防止重放攻击; RFC 6238 清楚地说明了这一点

    The verifier MUST NOT accept the second attempt of the OTP after the successful validation has been issued for the first OTP, which ensures one-time only use of an OTP.



    我想知道是否有推荐的方法来实现保护。由于 OTP token 是基于时间的,我正在考虑将最后一次成功登录存储在用户模型上,并确保每 30 秒时间片只有一次成功登录。这当然意味着用户模型上的同步。有更好的方法吗?

    谢谢你。

    --

    PS:由于这是一个关于安全的问题,我正在寻找来自可靠和/或官方来源的答案。谢谢你。

    最佳答案

    为了回答我自己的问题,经过进一步研究,这就是我实现它的方式。

    我有一个提供者作为实现 AuthenticationProvider 的 pojo .它故意不是 Bean/组件。否则 Spring 会将其注册为唯一的 Provider。

    public class MfaAuthenticationProvider implements AuthenticationProvider {
    private final AccountService accountService;

    @Override
    public Authentication authenticate(Authentication authentication) {
    // here be code
    }

    在我的 SecurityConfig 中,我让 Spring Autowiring AuthenticationManagerBuilder并手动注入(inject)我的 MfaAuthenticationProvider
    @Configuration
    @EnableWebSecurity
    public class SecurityConfig extends WebSecurityConfigurerAdapter {
    private final AuthenticationManagerBuilder authenticationManagerBuilder;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
    // other code
    authenticationManagerBuilder.authenticationProvider(getMfaAuthenticationProvider());
    // more code
    }

    // package private for testing purposes.
    MfaAuthenticationProvider getMfaAuthenticationProvider() {
    return new MfaAuthenticationProvider(accountService);
    }

    在标准身份验证之后,如果用户启用了 MFA,则他们将使用授予的权限 进行预身份验证PRE_AUTHENTICATED_MFA_REQUIRED .这允许他们访问单个端点 /auth/mfa-token .
    此端点从有效的 JWT 和提供的 TOTP 中获取用户名,并将其发送到 authenticate() authenticationManagerBuilder 的方法,它选择 MfaAuthenticationProvider因为它可以处理 OneTimePasswordAuthenticationToken .
        var authenticationToken = new OneTimePasswordAuthenticationToken(usernameFromJwt, providedOtp);
    var authentication = authenticationManagerBuilder.getObject().authenticate(authenticationToken);

    关于spring-boot - 使用 Spring Boot 2 和 Spring Security 5 进行多因素身份验证,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59918013/

    28 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com