【问题标题】:In addition to token based authentication, allow Rest api endpoint with http basic auth除了基于令牌的身份验证之外,还允许带有 http 基本身份验证的 Rest api 端点
【发布时间】:2015-01-11 07:39:42
【问题描述】:

我最近创建了一个带有以下 .yo-rc.json 的 jhipster 应用程序

{
    "generator-jhipster": {
    "baseName": "cmpayments",
    "packageName": "au.com.cmx.myapp",
    "packageFolder": "au/com/cmx/myapp",
    "authenticationType": "token",
    "hibernateCache": "no",
    "clusteredHttpSession": "no",
    "websocket": "no",
    "databaseType": "sql",
    "devDatabaseType": "postgresql",
    "prodDatabaseType": "postgresql",
    "useCompass": false,
    "buildTool": "maven",
    "frontendBuilder": "gulp",
    "javaVersion": "8"
  }
}

我喜欢在 webapp 上使用基于令牌的身份验证,但我希望服务器仅使用 http 基本身份验证来公开 REST api 调用。我已经为此奋斗了一段时间,但我对 Spring 安全性完全陌生,我希望有人已经做到了这一点并且可以帮助我。

我尝试按照此处的解决方案进行操作: Basic and form based authentication with Spring security Javaconfig

我在 SecurityConfiguration.java 中使用@Order(1) 创建了第二个配置

@Configuration
@Order(1)
public static class ApiWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {


    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication().withUser("api").password("pass").roles("API");
    }

    protected void configure(HttpSecurity http) throws Exception {
        http
            .csrf()
            .disable()
            .authorizeRequests()
            .antMatchers("/basicAuthApi/**").hasRole("API")
            .and()
            .httpBasic();
    }
}

这行得通。如果我使用 api/pass 凭据以外的任何其他内容访问 /basicAuthApi 下的端点,我会得到 401。是的。

但是,在此之后,当我以管理员/管理员(或用户/用户)身份登录 webapp 时,我以匿名用户身份登录。如果我在 SecurityConfiguration.java 中注释掉额外的 @Configuration 并重新启动应用程序,该问题就会消失,我会以管理员(或用户)的身份正确登录。

有趣的是,我尝试将第二个@Configuration 的顺序更改为@Order(101),因为我在某个基类中的某个位置看到了@Order(100)。在这种情况下,webapp 上的管理员和用户登录可以正常工作。但是其余的 api 调用不再安全,即即使密码错误也能成功。

有谁知道我做错了什么?

谢谢 达利克

【问题讨论】:

    标签: java spring-security spring-boot jhipster


    【解决方案1】:

    替换原来的SecurityConfiguration.configure:

    http
            .csrf()
            .ignoringAntMatchers("/websocket/**")
        .and()
            .addFilterAfter(new CsrfCookieGeneratorFilter(), CsrfFilter.class)
            .exceptionHandling()
            .authenticationEntryPoint(authenticationEntryPoint)
        .and()
            .rememberMe()
            .rememberMeServices(rememberMeServices)
            .rememberMeParameter("remember-me")
            .key(env.getProperty("jhipster.security.rememberme.key"))
        .and()
            .formLogin()
            .loginProcessingUrl("/api/authentication")
            .successHandler(ajaxAuthenticationSuccessHandler)
            .failureHandler(ajaxAuthenticationFailureHandler)
            .usernameParameter("j_username")
            .passwordParameter("j_password")
            .permitAll()
        .and()
            .logout()
            .logoutUrl("/api/logout")
            .logoutSuccessHandler(ajaxLogoutSuccessHandler)
            .deleteCookies("JSESSIONID")
            .permitAll()
        .and()
            .headers()
            .frameOptions()
            .disable()
        .and()
            .authorizeRequests()
            .antMatchers("/api/register").permitAll()
            .antMatchers("/api/activate").permitAll()
            .antMatchers("/api/authenticate").permitAll()
            .antMatchers("/api/account/reset_password/init").permitAll()
            .antMatchers("/api/account/reset_password/finish").permitAll()
            .antMatchers("/api/logs/**").hasAuthority(AuthoritiesConstants.ADMIN)
            .antMatchers("/api/**").authenticated()
            .antMatchers("/metrics/**").hasAuthority(AuthoritiesConstants.ADMIN)
            .antMatchers("/health/**").hasAuthority(AuthoritiesConstants.ADMIN)
            .antMatchers("/trace/**").hasAuthority(AuthoritiesConstants.ADMIN)
            .antMatchers("/dump/**").hasAuthority(AuthoritiesConstants.ADMIN)
            .antMatchers("/shutdown/**").hasAuthority(AuthoritiesConstants.ADMIN)
            .antMatchers("/beans/**").hasAuthority(AuthoritiesConstants.ADMIN)
            .antMatchers("/configprops/**").hasAuthority(AuthoritiesConstants.ADMIN)
            .antMatchers("/info/**").hasAuthority(AuthoritiesConstants.ADMIN)
            .antMatchers("/autoconfig/**").hasAuthority(AuthoritiesConstants.ADMIN)
            .antMatchers("/env/**").hasAuthority(AuthoritiesConstants.ADMIN)
            .antMatchers("/trace/**").hasAuthority(AuthoritiesConstants.ADMIN)
            .antMatchers("/api-docs/**").hasAuthority(AuthoritiesConstants.ADMIN)
            .antMatchers("/protected/**").authenticated();
    

    这个:

    http
            .csrf()
            .ignoringAntMatchers("/websocket/**")
        .and()
            .csrf()
            .ignoringAntMatchers("/basicAuthApi/**")
        .and()
            .addFilterAfter(new CsrfCookieGeneratorFilter(), CsrfFilter.class)
            .exceptionHandling()
            .authenticationEntryPoint(authenticationEntryPoint)
        .and()
            .rememberMe()
            .rememberMeServices(rememberMeServices)
            .rememberMeParameter("remember-me")
            .key(env.getProperty("jhipster.security.rememberme.key"))
        .and()
            .formLogin()
            .loginProcessingUrl("/api/authentication")
            .successHandler(ajaxAuthenticationSuccessHandler)
            .failureHandler(ajaxAuthenticationFailureHandler)
            .usernameParameter("j_username")
            .passwordParameter("j_password")
            .permitAll()
        .and()
            .logout()
            .logoutUrl("/api/logout")
            .logoutSuccessHandler(ajaxLogoutSuccessHandler)
            .deleteCookies("JSESSIONID")
            .permitAll()
        .and()
            .headers()
            .frameOptions()
            .disable()
        .and()
            .authorizeRequests()
            .antMatchers("/api/register").permitAll()
            .antMatchers("/api/activate").permitAll()
            .antMatchers("/api/authenticate").permitAll()
            .antMatchers("/api/account/reset_password/init").permitAll()
            .antMatchers("/api/account/reset_password/finish").permitAll()
            .antMatchers("/api/logs/**").hasAuthority(AuthoritiesConstants.ADMIN)
            .antMatchers("/api/**").authenticated()
            .antMatchers("/metrics/**").hasAuthority(AuthoritiesConstants.ADMIN)
            .antMatchers("/health/**").hasAuthority(AuthoritiesConstants.ADMIN)
            .antMatchers("/trace/**").hasAuthority(AuthoritiesConstants.ADMIN)
            .antMatchers("/dump/**").hasAuthority(AuthoritiesConstants.ADMIN)
            .antMatchers("/shutdown/**").hasAuthority(AuthoritiesConstants.ADMIN)
            .antMatchers("/beans/**").hasAuthority(AuthoritiesConstants.ADMIN)
            .antMatchers("/configprops/**").hasAuthority(AuthoritiesConstants.ADMIN)
            .antMatchers("/info/**").hasAuthority(AuthoritiesConstants.ADMIN)
            .antMatchers("/autoconfig/**").hasAuthority(AuthoritiesConstants.ADMIN)
            .antMatchers("/env/**").hasAuthority(AuthoritiesConstants.ADMIN)
            .antMatchers("/trace/**").hasAuthority(AuthoritiesConstants.ADMIN)
            .antMatchers("/api-docs/**").hasAuthority(AuthoritiesConstants.ADMIN)
            .antMatchers("/protected/**").authenticated()
        .and()
            .authorizeRequests()
            .antMatchers("/basicAuthApi/**")
            .hasAuthority(AuthoritiesConstants.USER).and().httpBasic();
    

    我只添加了:

    .and()
            .csrf()
            .ignoringAntMatchers("/basicAuthApi/**")
    

    和:

    .and()
            .authorizeRequests()
            .antMatchers("/basicAuthApi/**")
            .hasAuthority(AuthoritiesConstants.USER).and().httpBasic()
    

    您也可以创建一个只能访问这些网络服务的新权限。

    【讨论】:

      【解决方案2】:

      关于顺序的介绍:如果您不指定一个,则默认顺序是映射到可能的最低优先级的最大可能数字(因为较低的顺序转换为较高的优先级)。因此,当您添加 order=1 的配置时,您有两个配置,其中 order=1 的新配置具有更高的优先级并首先被检查。

      在您描述两种配置存在的情况下,会发生以下情况: 您尝试以 admin/admin(或用户/用户)身份登录 webapp,但 spring security 首先检查 order=1 的配置,该配置具有 ant matcher " .antMatchers("/basicAuthApi/**").hasRole("API")"。它显然不匹配,因为您指向的网址是该网站的网址,但是安全性不会失败,因为您缺少 .anyRequest().authenticated() 以使安全检查对于未能通过身份验证的用户实际上失败是必需的。如果没有这个,您实际上通过了安全检查,尽管您没有经过身份验证,即您被视为具有匿名用户访问权限的匿名用户。由于该配置的 spring security 成功,它甚至不检查与网站相关的另一个。

      【讨论】:

        【解决方案3】:

        我找到了适合我的解决方案。我意识到我不需要另一个@Configuration,因为默认的 jhipster 配置不会重定向到登录页面以进行未经身份验证的访问 - 它返回一个 401,这也是我想要的 REST api。 所以我只是用我想用于 REST api 的用户名和密码注册了一个用户,并在

        中的 configure 方法的底部添加了以下行

        OAuth2ServerConfiguration.ResourceServerConfiguration

                    `.antMatchers("/basicAuthApi/**").hasAuthority(AuthoritiesConstants.USER).and().httpBasic();`
        

        我现在将尝试通过创建一个 API 角色并将该角色分配给需要调用 REST API 的用户来改进这一点

        如果有人知道,我仍然想知道为什么我最初的尝试会出现这些问题。

        干杯 达利克

        【讨论】:

          猜你喜欢
          • 2017-11-27
          • 1970-01-01
          • 2021-01-25
          • 2016-07-16
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-04-19
          相关资源
          最近更新 更多