Spring Security Oauth2 : Possible CSRF detected


Spring Security Oauth2 : Possible CSRF detected

使用Spring Security 作為 Oauth2 授權服務器時,在授權服務器登錄授權后,重定向到客戶端服務器時,出現了401 Unauthorized 錯誤。明明已經授權了,為何還會未授權了。

跟蹤代碼發現,拋出了這個異常:

"Possible CSRF detected - state parameter was required but no state could be found"
導致這個異常的原因是,我在本地部署調試授權服務程序,和客戶端服務程序,均采用的是localhost域名,只是端口不同,這就導致兩個web程序在寫Session的cookie標識id(JSESSIONID)
時會被覆蓋。

具體發送的場景流程是,授權服務登錄授權后,會重定向到客戶端的
授權地址,這時會在session域中取出OAuth2ClientContext ,代碼在OAuth2RestOperationsConfiguration類中:
 @Bean
 @Scope(value = "session", proxyMode = ScopedProxyMode.INTERFACES)
 public DefaultOAuth2ClientContext oauth2ClientContext() {
     return new DefaultOAuth2ClientContext(this.accessTokenRequest);
}

   此時,由於Session的標識id被覆蓋,自然認為不在一個會話中,那就不會取到原來在客戶端要求授權跳轉前存放的OAuth2ClientContext,也就導致了爆出這個異常:

private MultiValueMap<String, String> getParametersForTokenRequest(AuthorizationCodeResourceDetails resource,
			AccessTokenRequest request) {

		MultiValueMap<String, String> form = new LinkedMultiValueMap<String, String>();
		form.set("grant_type", "authorization_code");
		form.set("code", request.getAuthorizationCode());

		Object preservedState = request.getPreservedState();
		if (request.getStateKey() != null || stateMandatory) {
			// The token endpoint has no use for the state so we don't send it back, but we are using it
			// for CSRF detection client side...
			if (preservedState == null) {
				throw new InvalidRequestException(
						"Possible CSRF detected - state parameter was required but no state could be found");
			}
		}

		//省略代碼...
return form; }

 那么如何解決這個問題呢?

   1.為不同web程序采用不同的域名,由於是本地部署,那么可以為本機配置幾個127.0.0.1 的 域名,如同localhost 指向 本機回還地址一樣。這個本機域名配置可以自行百度。

   2.為session的標識id采用不同的名稱,如授權服務器用SESSIONID,客戶端JSESSIONID不變.(如果多個客戶端,那就重命名,以免干涉),以下是如何設置:

      2.1   Spring Mvc  web.xml 

 <session-config>
  <cookie>
<name>SESSIONID</name>
</cookie> </session-config>
 
        

     2.2 Spring MVC JavaConfig

public class WebInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
  @Override
  public void onStartup(ServletContext servletContext) throws ServletException {
    super.onStartup(servletContext);
    servletContext.getSessionCookieConfig().setName("SESSIONID");
  }

//省略其他配置 }

 2.3 SpringBoot 

@SpringBootApplication
@ComponentScan(basePackages = "com.test")
public class LoginApplication implements ServletContextInitializer {
    public static void main(String[] args) {
        SpringApplication.run(LoginApplication.class, args);
    }

    @Override
    public void onStartup(ServletContext servletContext)
            throws ServletException {
        servletContext.getSessionCookieConfig().setName("SESSIONID");
    }
}

  或者在application.yml 文件中配置:

server:
  port: 8081
  tomcat:
    uri-encoding: UTF-8
  session: cookie: name: SESSIONID

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM