SpringSecurity支持WebAuthn认证

WebAuthn是无密码身份验证技术,解决了密码泄露的风险,主流的浏览器都支持。有很多开源的类库实现了WebAuthn规范,Java下流行的类库有:

Spring Security官方暂时未支持WebAuthn,可以用webauthn4jwebauthn4j-spring-security项目,它将webauthn4j和Spring Security打通,项目还处于开发阶段,设计上可能还会调整。但我们可以通过项目里的demo,很好的学习怎么实现WebAuthn。简单介绍一下webauthn4j-spring-security中例子的打开方式。

demo启动流程

  1. 克隆项目

git clone git@github.com:webauthn4j/webauthn4j-spring-security.git
  1. 打包前端资源

cd webauthn4j-spring-security/samples/lib/spa-angular-client
npm install

PS: 这里可能会碰到打包异常,是@angular/cdk包版本和其他模块版本冲突了,将@angular/cdk改成“13.3.9”就能正常打包

npm ERR! code ERESOLVE
npm ERR! ERESOLVE unable to resolve dependency tree
npm ERR! 
npm ERR! While resolving: sample-angular-client@0.0.0
npm ERR! Found: @angular/common@13.3.12
npm ERR! node_modules/@angular/common
npm ERR!   @angular/common@"^13.3.11" from the root project
npm ERR! 
npm ERR! Could not resolve dependency:
npm ERR! peer @angular/common@"^15.0.0 || ^16.0.0" from @angular/cdk@15.2.1
npm ERR! node_modules/@angular/cdk
npm ERR!   @angular/cdk@"^15.1.2" from the root project
npm ERR! 
npm ERR! Fix the upstream dependency conflict, or retry
npm ERR! this command with --force, or --legacy-peer-deps
npm ERR! to accept an incorrect (and potentially broken) dependency resolution.
  1. 启动项目

cd webauthn4j-spring-security
./gradlew build
./gradlew samples:spa:bootRun
  1. 查看登录页

  1. 访问:http://localhost:8080/,就会自动跳转到[http://localhost:8080/angular/login](http://localhost:8080/angular/login)

HttpSecurity核心配置

@Bean
public SecurityFilterChain filterChain(HttpSecurity http, AuthenticationManager authenticationManager) throws Exception {
    // WebAuthn Login
    http.apply(WebAuthnLoginConfigurer.webAuthnLogin())
            .usernameParameter("username")
            .passwordParameter("password")
            .credentialIdParameter("credentialId")
            .clientDataJSONParameter("clientDataJSON")
            .authenticatorDataParameter("authenticatorData")
            .signatureParameter("signature")
            .clientExtensionsJSONParameter("clientExtensionsJSON")
            .loginProcessingUrl("/login")
            .attestationOptionsEndpoint()
            .rp()
            .name("WebAuthn4J Spring Security Sample")
            .and()
            .pubKeyCredParams(
                    new PublicKeyCredentialParameters(PublicKeyCredentialType.PUBLIC_KEY, COSEAlgorithmIdentifier.RS256), // Windows Hello
                    new PublicKeyCredentialParameters(PublicKeyCredentialType.PUBLIC_KEY, COSEAlgorithmIdentifier.ES256) // FIDO U2F Key, etc
            )
            .extensions()
            .credProps(true)
            .and()
            .assertionOptionsEndpoint()
            .and()
            .successHandler(authenticationSuccessHandler)
            .failureHandler(authenticationFailureHandler)
            .and()
            .authenticationManager(authenticationManager);

    http.headers(headers -> {
        // 'publickey-credentials-get *' allows getting WebAuthn credentials to all nested browsing contexts (iframes) regardless of their origin.
        headers.permissionsPolicy(config -> config.policy("publickey-credentials-get *"));
        // Disable "X-Frame-Options" to allow cross-origin iframe access
        headers.frameOptions().disable();
    });

    // Logout
    http.logout()
            .logoutUrl("/logout")
            .logoutSuccessHandler(logoutSuccessHandler);

    // Authorization
    http.authorizeRequests()
            .mvcMatchers("/").permitAll()
            .mvcMatchers("/static/**").permitAll()
            .mvcMatchers("/angular/**").permitAll()
            .mvcMatchers("/webjars/**").permitAll()
            .mvcMatchers("/favicon.ico").permitAll()
            .mvcMatchers("/api/auth/status").permitAll()
            .mvcMatchers(HttpMethod.GET, "/login").permitAll()
            .mvcMatchers(HttpMethod.POST, "/api/profile").permitAll()
            .mvcMatchers("/health/**").permitAll()
            .mvcMatchers("/info/**").permitAll()
            .mvcMatchers("/h2-console/**").denyAll()
            .mvcMatchers("/api/admin/**").access("hasRole('ADMIN_ROLE') and isAuthenticated()")
            .anyRequest().access("@webAuthnSecurityExpression.isWebAuthnAuthenticated(authentication) || hasAuthority('SINGLE_FACTOR_AUTHN_ALLOWED')");

    http.sessionManagement()
            .sessionAuthenticationFailureHandler(authenticationFailureHandler);

    http.exceptionHandling()
            .authenticationEntryPoint(authenticationEntryPoint)
            .accessDeniedHandler(accessDeniedHandler);

    // As WebAuthn has its own CSRF protection mechanism (challenge), CSRF token is disabled here
    http.csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse());
    http.csrf().ignoringAntMatchers("/webauthn/**");

    return http.build();
}

这个方法将SpringSecurity需要的配置基本都说清楚了,除了#1、#2跟WebAuthn直接相关,其他几点都是SpringSecurity常规配置。

  1. 添加了自定义的WebAuthnLoginConfigurer描述登录页面的URL、字段名等信息

  1. 通过pubKeyCredParams描述服务器可接受的公钥类型的对象数组。

  1. 设置自定义的authenticationManager、successHandler、failureHandler等

  1. 设置http的header

  1. 设置authorizeRequests控制权限

  1. 设置session和exceptionHandling

  1. 设置Csrf配置

引用

体验WebAuthn登录: https://webauthn.io/
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

李昂的数字之旅

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值