服务器未在登录请求中响应(Spring Security)。

huangapple go评论94阅读模式
英文:

Server not responding at login request with Spring Security

问题

以下是翻译好的内容:

我正在使用Spring SecurityJWT来保护一个REST API(我没有使用Spring Boot)。

当我尝试发送认证请求(/login)到我的REST API时,Postman上显示无法获取任何响应

这是我的JWT过滤器:

public class JwtAuthenticationFilter extends UsernamePasswordAuthenticationFilter {

    ...

    public AuthenticationFilter(AuthenticationManager authenticationManager) {
        super.setAuthenticationManager(authenticationManager);
    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
        try {
            ... // 从请求中获取凭证
            return getAuthenticationManager().authenticate(new UsernamePasswordAuthenticationToken(credentials.login, credentials.password));
        } 
        catch (IOException e) { throw new RuntimeException(e); }
    }

    @Override
    protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain,
            Authentication authResult) throws IOException, ServletException {

        ... // 生成jwtToken

        response.setHeader("Authorization", jwtToken);
    }
}

当我调试我的应用时,一切都正常工作,并且successfulAuthentication方法被执行,我得到正确的令牌插入到请求的头部response.setHeader("Authorization", jwtToken);

但之后就好像我的REST API(或Spring Security或Tomcat)没有发送任何响应回来!

这是安全配置:

@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    ...

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()
            .authorizeRequests()
                .anyRequest().authenticated()
            .and()
                .addFilter(new JwtAuthenticationFilter(authenticationManager()));
        http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
    }
    
    ...
}

对于除了/login之外的其他HTTP请求,在Postman中我得到了(403)的HTML响应,而不是JSON响应。

<!doctype html>
<html lang="en">

<head>
    <title>HTTP Status 403 – Forbidden</title>
    ...

所以为什么我的服务器没有响应/login请求?为什么Spring Security没有为所有HTTP请求发送JSON响应?

/login请求之后的日志:

DEBUG o.s.security.web.FilterChainProxy - /login 在附加过滤器链的第1个位置中;触发过滤器: 'WebAsyncManagerIntegrationFilter'
DEBUG o.s.security.web.FilterChainProxy - /login 在附加过滤器链的第2个位置中;触发过滤器: 'SecurityContextPersistenceFilter'
DEBUG o.s.security.web.FilterChainProxy - /login 在附加过滤器链的第3个位置中;触发过滤器: 'HeaderWriterFilter'
DEBUG o.s.security.web.FilterChainProxy - /login 在附加过滤器链的第4个位置中;触发过滤器: 'LogoutFilter'
DEBUG o.s.security.web.util.matcher.OrRequestMatcher - 尝试使用Ant匹配器 [模式='/logout', GET] 进行匹配
DEBUG o.s.security.web.util.matcher.AntPathRequestMatcher - 请求 'POST /login' 不匹配 'GET /logout'
DEBUG o.s.security.web.util.matcher.OrRequestMatcher - 尝试使用Ant匹配器 [模式='/logout', POST] 进行匹配
DEBUG o.s.security.web.util.matcher.AntPathRequestMatcher - 正在检查请求匹配情况 : '/login'; 与 '/logout' 不匹配
DEBUG o.s.security.web.util.matcher.OrRequestMatcher - 尝试使用Ant匹配器 [模式='/logout', PUT] 进行匹配
DEBUG o.s.security.web.util.matcher.AntPathRequestMatcher - 请求 'POST /login' 不匹配 'PUT /logout'
DEBUG o.s.security.web.util.matcher.OrRequestMatcher - 尝试使用Ant匹配器 [模式='/logout', DELETE] 进行匹配
DEBUG o.s.security.web.util.matcher.AntPathRequestMatcher - 请求 'POST /login' 不匹配 'DELETE /logout'
DEBUG o.s.security.web.util.matcher.OrRequestMatcher - 没有找到匹配项
DEBUG o.s.security.web.FilterChainProxy - /login 在附加过滤器链的第5个位置中;触发过滤器: 'JwtAuthenticationFilter'
DEBUG o.s.security.web.util.matcher.AntPathRequestMatcher - 正在检查请求匹配情况 : '/login'; 与 '/login' 匹配
DEBUG security.JwtAuthenticationFilter - 请求正在处理认证
DEBUG o.s.security.authentication.ProviderManager - 使用 o.s.security.authentication.dao.DaoAuthenticationProvider 进行认证尝试
DEBUG o.s.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler - 为共享的EntityManager调用创建新的EntityManager
Hibernate: select ... 
DEBUG o.s.security.web.header.writers.HstsHeaderWriter - 未注入HSTS头,因为它与请求匹配器 o.s.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher@5b319bff 不匹配
DEBUG o.s.security.web.context.SecurityContextPersistenceFilter - 现在已清除SecurityContextHolder,因为请求处理已完成
英文:

I am securing a REST API with Spring Security and JWT (i'm not using Spring Boot).

When i try to send an authentication request (/login) to my REST API i got Could not get any response on Postman

服务器未在登录请求中响应(Spring Security)。

Here is my JWT filter

public class JwtAuthenticationFilter extends UsernamePasswordAuthenticationFilter {

	...

	public AuthenticationFilter(AuthenticationManager authenticationManager) {
		super.setAuthenticationManager(authenticationManager);
	}
	
	@Override
	public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
		try {
			... // getting the credentials from the request
			return getAuthenticationManager().authenticate(new UsernamePasswordAuthenticationToken(credentials.login, credentials.password));
		} 
		catch (IOException e) { throw new RuntimeException(e); }
	}

	@Override
	protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain,
			Authentication authResult) throws IOException, ServletException {

		... // generating the jwtToken;

		response.setHeader(&quot;Authorization&quot;, jwtToken);
	}
}

When i am debugging my app everything works fine and the successfulAuthentication method is executed and i get the right token inserted in the header request response.setHeader(&quot;Authorization&quot;, jwtToken);.

But after that it's like my REST API (or Spring Security or Tomcat) don't send any response back !

Here is the security config :

@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

	...

	@Override
	protected void configure(HttpSecurity http) throws Exception {
		http.csrf().disable()
			.authorizeRequests()
				.anyRequest().authenticated()
			.and()
				.addFilter(new JwtAuthenticationFilter(authenticationManager()));
		http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);

	}
    
    ...
}

For other HTTP requests other than /login i got a (403) HTML response in Postman and NOT a JSON response.

&lt;!doctype html&gt;
&lt;html lang=&quot;en&quot;&gt;

&lt;head&gt;
	&lt;title&gt;HTTP Status 403 – Forbidden&lt;/title&gt;
	...

So Why my server is not responding at /login request ? and why Spring security is not sending JSON response for all the http requests ?

Logs after /login request :

DEBUG o.s.security.web.FilterChainProxy - /login at position 1 of 11 in additional filter chain; firing Filter: &#39;WebAsyncManagerIntegrationFilter&#39;
DEBUG o.s.security.web.FilterChainProxy - /login at position 2 of 11 in additional filter chain; firing Filter: &#39;SecurityContextPersistenceFilter&#39;
DEBUG o.s.security.web.FilterChainProxy - /login at position 3 of 11 in additional filter chain; firing Filter: &#39;HeaderWriterFilter&#39;
DEBUG o.s.security.web.FilterChainProxy - /login at position 4 of 11 in additional filter chain; firing Filter: &#39;LogoutFilter&#39;
DEBUG o.s.security.web.util.matcher.OrRequestMatcher - Trying to match using Ant [pattern=&#39;/logout&#39;, GET]
DEBUG o.s.security.web.util.matcher.AntPathRequestMatcher - Request &#39;POST /login&#39; doesn&#39;t match &#39;GET /logout&#39;
DEBUG o.s.security.web.util.matcher.OrRequestMatcher - Trying to match using Ant [pattern=&#39;/logout&#39;, POST]
DEBUG o.s.security.web.util.matcher.AntPathRequestMatcher - Checking match of request : &#39;/login&#39;; against &#39;/logout&#39;
DEBUG o.s.security.web.util.matcher.OrRequestMatcher - Trying to match using Ant [pattern=&#39;/logout&#39;, PUT]
DEBUG o.s.security.web.util.matcher.AntPathRequestMatcher - Request &#39;POST /login&#39; doesn&#39;t match &#39;PUT /logout&#39;
DEBUG o.s.security.web.util.matcher.OrRequestMatcher - Trying to match using Ant [pattern=&#39;/logout&#39;, DELETE]
DEBUG o.s.security.web.util.matcher.AntPathRequestMatcher - Request &#39;POST /login&#39; doesn&#39;t match &#39;DELETE /logout&#39;
DEBUG o.s.security.web.util.matcher.OrRequestMatcher - No matches found
DEBUG o.s.security.web.FilterChainProxy - /login at position 5 of 11 in additional filter chain; firing Filter: &#39;JwtAuthenticationFilter&#39;
DEBUG o.s.security.web.util.matcher.AntPathRequestMatcher - Checking match of request : &#39;/login&#39;; against &#39;/login&#39;
DEBUG security.JwtAuthenticationFilter - Request is to process authentication
DEBUG o.s.security.authentication.ProviderManager - Authentication attempt using o.s.security.authentication.dao.DaoAuthenticationProvider
DEBUG o.s.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler - Creating new EntityManager for shared EntityManager invocation
Hibernate: select ... 
DEBUG o.s.security.web.header.writers.HstsHeaderWriter - Not injecting HSTS header since it did not match the requestMatcher o.s.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher@5b319bff
DEBUG o.s.security.web.context.SecurityContextPersistenceFilter - SecurityContextHolder now cleared, as request processing completed

答案1

得分: 0

以下是翻译好的内容:

首先要讨论的是,你收到的响应不是JSON(对于所有其他请求)。首先,URL端点上的方法应该被分配以生成你正在请求的内容。而你想要的内容,可以在Postman中的头部中提到,对于JSON,它应该是Accepts: Application/json

另一件事是为什么服务器没有响应你的登录请求,原因是你的情况下应该有最佳配置。

http.csrf().disable()
    //你可以给出你想要允许的请求
    .anyRequest().authenticated()
    .and()
    .addFilter(new JwtAuthenticationFilter(authenticationManager()));
英文:

The very first things, I will talk about the response the that you get is not in Json(For all other requests). See, first the method at the url endpoint should be assigned to produce the content that you're requesting. And the content that you want, you can mention in the headers in postman for json it should be Accepts : Application/json

The other thing is why the server is not responding to your login request is that, best configuration should be in your case.

http.csrf().disable()
             //You can give the request that you want to allow
         .anyRequest().authenticated()
            .and()
                .addFilter(new JwtAuthenticationFilter(authenticationManager()));

答案2

得分: 0

对于服务器不响应的问题,这是一个愚蠢的错误,在我的属性文件中,我把授权头的名称放在了双引号中:

security.token.header-string=&quot;Authorization&quot;

而应该是:

security.token.header-string=Authorization

对于服务器未以 JSON 格式响应的部分,我遵循了这个答案

因此,我不得不实现自定义的 authenticationEntryPointaccessDeniedHandlerauthenticationSuccessHandlerauthenticationFailureHandler,如下所示:

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.csrf().disable();
    http
        .authorizeRequests()
            .anyRequest().authenticated()
        .and()
        .addFilter(getJwtAuthenticationFilter())
        .exceptionHandling()
            .authenticationEntryPoint((request, response, exception) -> {
                response.setStatus(401);
            })
            .accessDeniedHandler((request, response, exception) -> {
                response.setStatus(403);
            });
    http
        .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}

使用 JwtAuthenticationFilter

@Bean
private JwtAuthenticationFilter getJwtAuthenticationFilter() throws Exception {
    JwtAuthenticationFilter filter = new JwtAuthenticationFilter(authenticationManager());
    filter.setFilterProcessesUrl("/api/login");
    //filter.setAuthenticationSuccessHandler((request, response, authentication) -> {
    //    response.setStatus(200);
    //});
    filter.setAuthenticationFailureHandler((request, response, exception) -> {
        response.setStatus(401);
    });
    return filter;
}

我已经注释掉了 filter.setAuthenticationSuccessHandler(...) 这一行,因为我已经在我的 JwtAuthenticationFilter 类中覆盖了 successfulAuthentication 方法。

英文:

For the issue with the server not responding it was stupid mistake, In my properties file i have put the Authorization header name with double quote

security.token.header-string=&quot;Authorization&quot;

Instead of

security.token.header-string=Authorization

For the part which the server not responding with JSON format i follow this answer

So i had to implement a custom authenticationEntryPoint, accessDeniedHandler, authenticationSuccessHandler and authenticationFailureHandler
like bellow :

@Override
protected void configure(HttpSecurity http) throws Exception {

	http.csrf().disable();
	http.
		authorizeRequests()
			.anyRequest().authenticated()
		.and()
        .addFilter(getJwtAuthenticationFilter())
		.exceptionHandling()
			.authenticationEntryPoint((request, response, exception) -&gt; {
				response.setStatus(401);
			})	
			.accessDeniedHandler((request, response, exception) -&gt; {
				response.setStatus(403);
			})
		;

	http.
		sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);

}

With the JwtAuthenticationFilter

@Bean
private JwtAuthenticationFilter getJwtAuthenticationFilter() throws Exception {

	JwtAuthenticationFilter filter = new JwtAuthenticationFilter(authenticationManager());
	
	filter.setFilterProcessesUrl(&quot;/api/login&quot;);

	//filter.setAuthenticationSuccessHandler((request, response, authentication) -&gt; {
	//    response.setStatus(200);
	//});

	filter.setAuthenticationFailureHandler((request, response, exception) -&gt; {
	    response.setStatus(401);
	});

	return filter;
}

I have comment the line filter.setAuthenticationSuccessHandler(...) because it will not be invoked since i already override the successfulAuthentication method on my JwtAuthenticationFilter class.
1: https://stackoverflow.com/a/32507217/1383538

huangapple
  • 本文由 发表于 2020年4月5日 12:39:21
  • 转载请务必保留本文链接:https://go.coder-hub.com/61038156.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定