如何忽略 Spring Security 中的端点?

Posted

技术标签:

【中文标题】如何忽略 Spring Security 中的端点?【英文标题】:How to ignore endpoint in Spring Security? 【发布时间】:2019-04-26 16:10:21 【问题描述】:

我正在尝试实现 JWT。我有两个端点:/api/auth/signin 用于身份验证,返回生成的 JWT 令牌,/api/auth/me 应该根据标头中的 JWT 令牌返回用户。我正在尝试将 Spring Security 配置为只有授权用户才能访问/api**,我需要排除/api/auth/signin 这是扩展 WebSecurityConfigurerAdapter 的类中的 configure() 方法:

@Override
protected void configure(HttpSecurity http) throws Exception 
    http.antMatcher("/api**")
            .httpBasic().disable()
            .csrf().disable()
            .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
            .and()
            .authorizeRequests()
                .antMatchers(HttpMethod.POST, "/api/auth/signin").permitAll()
                .anyRequest().authenticated()
            .and()
            .addFilterBefore(jwtAuthorizationFilter(), UsernamePasswordAuthenticationFilter.class);

但它仍然为/api/auth/signin 调用 JwtAuthorizationFilter。我还尝试通过以下方式忽略此端点:

@Override
public void configure(WebSecurity web) throws Exception 
    web.ignoring().antMatchers(HttpMethod.POST,"/api/auth/signin");

有没有其他方法可以忽略它,或者permitAll()ignoring() 应该以不同的方式使用?

【问题讨论】:

您确定在调用 /api/auth/signin 端点时使用 POST 请求吗?此外,登录端点是否有可能将您重定向到另一个端点?并且在重定向期间调用过滤器? @Selindek,是的,使用了 POST 请求。但即使我删除了 HttpMethod.POST,它仍然会调用 JwtAuthorizationFilter。而且它不会重定向到另一个端点。 UsernamePasswordAuthenticationFilter 是否在 JWT 过滤器之前介入? @RahulVedpathak,不,此过滤器在 JWT 过滤器之前不参与 我认为你应该使用 AuthenticationServerConfiguration 和 ResourceServerConfiguration 而不是手动配置 JWT。 【参考方案1】:

为什么不创建两种类型的端点:

    授权的 API:“/api/auth/**” 未经授权的 API:“/api/noauth/**”

然后只为“/api/auth/**”配置安全

【讨论】:

它不适用于无需身份验证即可使用资源且仅需要凭据进行编辑的情况。【参考方案2】:

您需要一个 AbstractAuthenticationProcessingFilter 过滤器来在 /api/auth/signin 上生成 JWT 令牌和一个 GenericFilterBean 来检索身份验证对象并将其放入 SecurityContextHolder

以下链接中有一个很好的示例:

https://auth0.com/blog/securing-spring-boot-with-jwts/

http.antMatcher("/api**")
                .httpBasic().disable()
                .csrf().disable()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
            // We filter the api/login requests
            .addFilterBefore(new JWTLoginFilter("/api/auth/signin", authenticationManager()),
                    UsernamePasswordAuthenticationFilter.class)
            // And filter other requests to check the presence of JWT in header
            .addFilterBefore(new jwtAuthorizationFilter(),
                    UsernamePasswordAuthenticationFilter.class);

而且我不确定是否可以从 响应正文中 JWTLoginFilter 中的successAuthentication()

示例在响应的授权标头中返回令牌。但如果你想在正文中返回令牌。您可以使用以下代码:

static void addAuthentication(HttpServletResponse res, String username) 
        String JWT = Jwts.builder()
                .setSubject(username)
                .setExpiration(new Date(System.currentTimeMillis() + EXPIRATIONTIME))
                .signWith(SignatureAlgorithm.HS512, SECRET)
                .compact();
//        res.addHeader(HEADER_STRING, TOKEN_PREFIX + " " + JWT);
        JSONObject tokenJson = new JSONObject();
        tokenJson.put(SecurityConstants.JWT_TOKEN, JWT);
        tokenJson.put(SecurityConstants.USERNAME, username);
        try(PrintWriter writer = res.getWriter()) 
            writer.print(tokenJson.toJSONString());
            writer.flush();
         catch (IOException e) 
            LOG.error("error ...");
        
//        res.addHeader(HEADER_STRING, TOKEN_PREFIX + " " + JWT);
    

【讨论】:

我看过这篇文章,但是在我的实现中,RestController中生成的JWT令牌,映射到/api/auth/signin,我需要让Spring Security忽略它。而且我不确定是否可以从响应正文中 JWTLoginFilter 中的successfulAuthentication() 返回生成的令牌。 如果您不想为签名请求调用 jwtAuthorizationFilter。你可以给你一个不同的前缀(比如不以“api”开头的身份验证/登录)***.com/questions/36795894/…我还更新了我的帖子,向你展示如何在正文中发送令牌

以上是关于如何忽略 Spring Security 中的端点?的主要内容,如果未能解决你的问题,请参考以下文章

如何将 Spring Security 的 CSRF 功能用于无状态端点?

Spring Security + Keycloak 授权:如何将端点与资源相关联?

如何仅在安全端点上应用 Spring Security 过滤器?

如何在spring security oauth2中分离访问令牌和刷新令牌端点

如何向 Spring Security 忽略的请求添加标头

如何在spring boot项目中忽略特定URL的spring security CSRF