当前位置: 首页 > 知识库问答 >
问题:

使用spring security为基本身份验证配置多种身份验证类型

宋翔
2023-03-14

我有一个需要以两种不同方式保护的API:

1) 对除1以外的所有请求URL使用JWT,该URL需要使用基本身份验证进行保护

2) 一个url的基本身份验证。

我已经为JWT和Basic Auth设置了安全配置。我的问题是,当我使用有效的用户名和密码请求基本的经过身份验证的URL时,它会成功地对我进行身份验证,并将数据存储在cassandra中。

然后,我希望必须通过/api/login为所有其他请求URL生成一个令牌,并将其添加到Authorization:Bearer{token}头中。。

但是,如果我通过Basic Auth进行了身份验证,那么我可以访问其他URL(受JWT auth保护),而无需在请求中添加令牌。

当我在没有使用基本身份验证的情况下访问受JWT保护的URL时,我必须在标头中发送令牌,它会按预期工作。。

我应该期待这个吗?正如我所相信的,即使我通过一个endpoint的基本身份验证进行了身份验证,我仍然应该在请求中为所有其他受保护的JWTendpoint发送令牌。。

我找到了这个答案:SpringBoot多重身份验证适配器

还有这篇文章:https://docs.spring.io/spring-security/site/docs/4.2.x/reference/htmlsingle/#multiple-httpsecurity

并尝试实施解决方案,但所解释的问题仍然存在。

安全配置类如下:

@Configuration
@EnableWebSecurity
public class SecurityHttpConfig extends WebSecurityConfigurerAdapter {

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

        @Value("${basic.auth.user}")
        private String basicAuthUsername;

        @Value("${basic.auth.password}")
        private String basicAuthPassword;

        @Value("${crashboxx.consume.endpoint}")
        private String crashBoxxConsumeEndpoint;

        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.csrf().disable().authorizeRequests().antMatchers("/v1/crash/consumeCrashBoxxEvent").hasRole("ADMIN").and()
                    .httpBasic().authenticationEntryPoint(getBasicAuthEntryPoint()).and().sessionManagement()
                    .sessionCreationPolicy(SessionCreationPolicy.STATELESS);// We don't need sessions to be created.
        }

        @Bean
        public CustomBasicAuthenticationEntryPoint getBasicAuthEntryPoint() {
            return new CustomBasicAuthenticationEntryPoint();
        }

        @Autowired
        public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
            PasswordEncoder encoder = PasswordEncoderFactories.createDelegatingPasswordEncoder();
            auth.inMemoryAuthentication().withUser(basicAuthUsername).password(encoder.encode(basicAuthPassword))
                    .roles("ADMIN");
        }

        @Bean
        public PasswordEncoder passwordEncoder() {
            return new BCryptPasswordEncoder();
        }
    }

    @Configuration
    @Order(2)
    public static class JwtWebSecurityConfig extends WebSecurityConfigurerAdapter {

        @Autowired
        private JwtAuthenticationEntryPoint unauthorizedHandler;

        @Autowired
        private JwtAuthenticationProvider jwtAuthenticationProvider;

        // Any endpoints that require no authorization should be added here..
        @Value("${api.login.endpoint}")
        private String loginEndpoint;

        @Autowired
        public void configureAuthentication(AuthenticationManagerBuilder authenticationManagerBuilder) {
            authenticationManagerBuilder.authenticationProvider(jwtAuthenticationProvider);
        }

        @Bean
        public JwtAuthenticationTokenFilter authenticationTokenFilterBean() {
            return new JwtAuthenticationTokenFilter();
        }

        @Override
        protected void configure(HttpSecurity httpSecurity) throws Exception {
            httpSecurity.csrf().disable().exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and()
                    .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
                    .authorizeRequests().antMatchers("/api/login").permitAll().anyRequest().authenticated();

            httpSecurity.addFilterBefore(authenticationTokenFilterBean(), UsernamePasswordAuthenticationFilter.class);
            httpSecurity.headers().cacheControl();
        }
    }

使用BasicAuthEntryPoint类:

public class CustomBasicAuthenticationEntryPoint extends BasicAuthenticationEntryPoint {

    private static final Gson gson = new Gson();

    @Override
    public void commence(final HttpServletRequest request, final HttpServletResponse response,
            final AuthenticationException authException) throws IOException, ServletException {
        // Authentication failed, send error response.
        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
        PrintWriter writer = response.getWriter();
        writer.println(gson.toJson("HTTP Status 401 : " + authException.getMessage()));
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        setRealmName("Realm");
        super.afterPropertiesSet();
    }

还有JWT impl:

@Component
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {

    @Value("${jwt.header}")
    private String tokenHeader;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException {
        final String requestHeader = request.getHeader(tokenHeader);
        // Ensure Auth Header contains 'Bearer'
        if (requestHeader != null && requestHeader.startsWith("Bearer ")) {
            String authToken = requestHeader.substring(7);
            JwtAuthentication authentication = new JwtAuthentication(authToken);
            SecurityContextHolder.getContext().setAuthentication(authentication);
        }
        chain.doFilter(request, response);
    }

我希望这是有意义的。。如果还有其他问题,请告诉我,但我似乎无法回避这个问题。

我首先添加了“特殊情况”,这是基本身份验证的一个网址,但仍然没有任何区别。

谢谢

共有2个答案

松和璧
2023-03-14

这是通过使用Praveen Kumar Lalasangi在上面的答案中提供的信息来解决的。

对configure(配置)方法的一个小改动就成功了。。更新内容包括:

@Override
    protected void configure(HttpSecurity http) throws Exception {
      http.csrf().disable()
      .antMatcher(crashBoxxConsumeEndpoint).authorizeRequests().anyRequest()
      .hasRole("ADMIN")
      .and().httpBasic().authenticationEntryPoint(getBasicAuthEntryPoint())
      .and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
    }
习华灿
2023-03-14

您在@order(1)的安全配置中发布的代码

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.csrf().disable().authorizeRequests().antMatchers("/v1/crash/consumeCrashBoxxEvent").hasRole("ADMIN").and()
            .httpBasic().authenticationEntryPoint(getBasicAuthEntryPoint()).and().sessionManagement()
            .sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}

如果这是您正在使用的确切代码,则不会咨询您的订单(2)配置。这将是死配置<让我解释一下
http。authorizeRequests()。antMatcher(“/**”)。authorizeRequests()在第一次配置中,您使用的是通配符,配置结果为

    如果用户已通过身份验证并具有角色ADMIN,则访问
  • /v1/崩溃/consumeCrashBoxxEvent
  • 如果用户经过身份验证,则访问URL的其余部分

让我猜猜发生了什么!
1.您正在点击URL/v1/崩溃/consumeCrashBoxxEvent任何URL您将被提示进行基本身份验证。
2.身份验证成功后,您可以访问任何URL,因为您是经过身份验证的用户。

但是,如果我通过Basic Auth进行了身份验证,那么我可以访问其他URL(受JWT auth保护),而无需在请求中添加令牌。

因为正如我所说,您可以访问任何URL,因为您是经过身份验证的用户

当我在没有使用基本身份验证的情况下访问受JWT保护的URL时,我必须在标头中发送令牌,它会按预期工作

检查您是否可以访问没有令牌。因为一旦您通过基本身份验证登录,服务器端就不会注销(即使您重新启动服务器)。只有关闭浏览器才能实现注销。因此,您通过关闭并再次启动浏览器来测试它。并通过不发送JWT令牌来测试它。
还要确保您的请求到达JwtAuthentiationTokenFilter,放置调试日志进行验证。

因为在您的问题中有很多抽象,除非发布完整的代码,否则很难准确预测发生了什么。

如果我的预测偏离实际,请在评论中告诉我。

 类似资料:
  • 我一直在努力遵循这个教程: https://www.baeldung.com/spring-security-basic-authentication 我创建了几个restendpoint,如下所示: 现在的问题是,每当我试图发送POST请求时,我都会得到以下错误消息: HTTP状态401-访问此资源需要完全身份验证 我尝试了两种方法来发送请求,一种是通过邮递员 1.1 401 set-cooki

  • 问题内容: 从HttpClient 4.3开始,我一直在使用HttpClientBuilder。我正在连接到具有基本身份验证的REST服务。我将凭据设置如下: 但是,这不起作用(我正在使用的REST服务返回401)。怎么了? 问题答案: 从此处的 抢先身份验证 文档中: http://hc.apache.org/httpcomponents-client- ga/tutorial/html/aut

  • 我想使用Spring Cloud实现OAuth2的令牌刷新。 我可以使用以下有效负载通过向发送请求来创建令牌: 但对于刷新令牌,则使用相同的路径。我还需要将用户名和密码发送到标题中,但我没有它们。我可以使用以下负载使用刷新令牌创建一个新令牌: Github代码

  • 我正在尝试将我的spring boot应用程序配置为登录zipkin服务器。问题是,该服务器受代理(具有基本身份验证)保护,我找不到任何描述如何使用spring sleuth配置授权的文档。 我尝试过使用这种配置: 但没有成功,日志显示: 我试过卷发,效果很好。 有人已经成功地用spring sleuth配置了身份验证吗?

  • 身份验证 PDF版下载 企业应用中的URL链接可以通过OAuth2.0验证接口来获取员工的身份信息。 通过此接口获取员工身份会有一定的时间开销。对于频繁获取员工身份的场景,建议采用如下方案: 企业应用中的URL链接直接填写企业自己的页面地址; 员工跳转到企业页面时,企业校验是否有代表员工身份的cookie,此cookie由企业生成; 如果没有获取到cookie,重定向到OAuth验证链接,获取员工

  • 目前我正在开发一个Java工具,它应该可以更新Confluence服务器页面。使用Curl一切都像一个符咒,但是当使用Postman或Java代码(HttpClient Java11)时,我得到了一个 HTTP状态401–未经授权 反应。 在下面的语句中使用curl curl--basic-u user:password-X PUT-H“内容类型:application/json”-d“@test