2013-05-17 58 views
8

當Spring使用基本身份驗證時,我遇到了與HTTP響應頭「Access-Control-Allow-Origin」相關的問題。當我手動進行身份驗證,如代碼波紋管(我使用REST):Spring Security,REST基本身份驗證問題

@RequestMapping(value = "/login", method = RequestMethod.POST, consumes = "application/json") 
@ResponseStatus(value = HttpStatus.OK) 
public void login(@RequestBody String body, HttpServletResponse response) 
     throws IOException { 
    try { 
     User user = gson.fromJson(body, User.class); 

     UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(
       usuario.getUsername(), usuario.getPassword()); 

     authenticationManager.authenticate(token); 
    } catch (BadCredentialsException e) { 
     response.sendError(HttpServletResponse.SC_UNAUTHORIZED); 
    } catch (Exception e) { 
     response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); 
    } 
} 

一切工作正常,我收到下面的HTTP響應:

HTTP/1.1 401 Unauthorized 
Server: Apache-Coyote/1.1 
Access-Control-Allow-Origin: null 
Access-Control-Allow-Credentials: true 
Content-Type: text/html;charset=utf-8 
Content-Length: 951 
Date: Fri, 17 May 2013 19:14:36 GMT 

,你可以看到,「訪問 - Control-Allow-Origin「出現在響應中。 這裏的一切都很好。我可以在我的ajax調用中發現401錯誤。

但是,當是自動執行的認證,如波紋管的代碼:在

HTTP/1.1 401 Unauthorized 
Server: Apache-Coyote/1.1 
WWW-Authenticate: Basic realm="Spring Security Application" 
Content-Type: text/html;charset=utf-8 
Content-Length: 981 
Date: Fri, 17 May 2013 19:41:08 GMT 

沒有「訪問控制允許來源」:

@RequestMapping(value = "/name", method = RequestMethod.POST, consumes = "application/json") 
@PreAuthorize("hasRole('ROLE_CUSTOMER')") 
public @ResponseBody String getName(HttpServletResponse response) throws IOException { 
    String json = null; 

    try { 
     User userSession = (User) SecurityContextHolder.getContext() 
       .getAuthentication().getPrincipal(); 

     Customer customer = customerDao.getNameByUsername(userSession.getUsername()); 

     json = gson.toJson(customer); 

    } catch (Exception e) { 
     response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); 
    } 

    return json; 
} 

HTTP響應是響應

谷歌瀏覽器的控制檯顯示以下錯誤:

Origin null is not allowed by Access-Control-Allow-Origin 

即使HTTP響應返回它(上面的響應),我的ajax調用不會返回401 Unauthorized錯誤,但會收到未知錯誤。

我發現對於所有瀏覽器,我需要HTTP響應中的「Access-Control-Allow-Origin」,否則它們會產生某種無聲錯誤,並且我的ajax調用將失敗(無法捕捉到401錯誤)。其實,JavaScript會默默地失敗。 XMLHttpRequest 不接受沒有「Access-Control-Allow-Origin」的HTTP響應。

如何讓Spring在HTTP響應中爲基本身份驗證注入此「Access-Control-Allow-Origin」?

這是我的Spring Security XML:

<?xml version="1.0" encoding="UTF-8"?> 
<beans xmlns="http://www.springframework.org/schema/beans" 
    xmlns:security="http://www.springframework.org/schema/security" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation=" 
      http://www.springframework.org/schema/beans 
      http://www.springframework.org/schema/beans/spring-beans-3.2.xsd 
      http://www.springframework.org/schema/security 
      http://www.springframework.org/schema/security/spring-security-3.1.xsd"> 

    <security:http create-session="stateless" entry-point-ref="authenticationEntryPoint"> 
     <security:intercept-url pattern="/customer/**" /> 
     <security:http-basic /> 
     <security:custom-filter ref="basicAuthenticationFilter" 
      after="BASIC_AUTH_FILTER" /> 
    </security:http> 

    <bean id="basicAuthenticationFilter" 
     class="org.springframework.security.web.authentication.www.BasicAuthenticationFilter"> 
     <property name="authenticationManager" ref="authenticationManager" /> 
     <property name="authenticationEntryPoint" ref="authenticationEntryPoint" /> 
    </bean> 

    <bean id="authenticationEntryPoint" 
     class="org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint"> 
     <property name="realmName" value="teste.com" /> 
    </bean> 

    <!-- It is responsible for validating the user's credentials --> 
    <security:authentication-manager alias="authenticationManager"> 

     <!-- It is responsible for providing credential validation to the AuthenticationManager --> 
     <security:authentication-provider> 
      <security:password-encoder ref="passwordEncoder" /> 

      <security:jdbc-user-service 
       data-source-ref="mySQLdataSource" 
       users-by-username-query="select username, password, enabled from usuario where username = ?" 
       authorities-by-username-query="select username, papel from autoridade where username = ?" /> 

     </security:authentication-provider> 

    </security:authentication-manager> 

    <bean class="org.springframework.security.crypto.password.StandardPasswordEncoder" 
     id="passwordEncoder" /> 

</beans> 

回答

11

剛剛發現我自己的方式:

首先,我真的不記得爲什麼我在這裏把這個線,但它搞亂我的代碼:

<security:http-basic /> 

其次,這個答案告訴我的路徑:Handle unauthorized error message for Basic Authentication in Spring Security。我必須創建一個自定義身份驗證入口點才能發送Access-Control-Allow-Origin的東西。

所以現在這是我的代碼:

<?xml version="1.0" encoding="UTF-8"?> 
<beans xmlns="http://www.springframework.org/schema/beans" 
    xmlns:security="http://www.springframework.org/schema/security" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation=" 
       http://www.springframework.org/schema/beans 
       http://www.springframework.org/schema/beans/spring-beans-3.2.xsd 
       http://www.springframework.org/schema/security 
       http://www.springframework.org/schema/security/spring-security-3.1.xsd"> 

    <security:http create-session="stateless" 
     entry-point-ref="authenticationEntryPoint"> 
     <security:intercept-url pattern="/api/admin/**" /> 
     <security:intercept-url pattern="/medico/**" /> 
     <!-- <security:http-basic /> --> 
     <security:custom-filter ref="basicAuthenticationFilter" 
      after="BASIC_AUTH_FILTER" /> 
    </security:http> 

    <bean id="basicAuthenticationFilter" 
     class="org.springframework.security.web.authentication.www.BasicAuthenticationFilter"> 
     <property name="authenticationManager" ref="authenticationManager" /> 
     <property name="authenticationEntryPoint" ref="authenticationEntryPoint" /> 
    </bean> 

      <!-- 
    <bean id="authenticationEntryPoint" 
     class="org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint"> 
     <property name="realmName" value="test.com" /> 
    </bean> --> 


    <bean id="authenticationEntryPoint" 
     class="com.test.util.PlainTextBasicAuthenticationEntryPoint"> 
     <property name="realmName" value="test.com" /> 
    </bean> 

    <!-- It is responsible for validating the user's credentials --> 
    <security:authentication-manager alias="authenticationManager"> 

     <!-- It is responsible for providing credential validation to the AuthenticationManager --> 
     <security:authentication-provider> 
      <security:password-encoder ref="passwordEncoder" /> 

      <security:jdbc-user-service 
       data-source-ref="mySQLdataSource" 
       users-by-username-query="select username, password, enabled from usuario where username = ?" 
       authorities-by-username-query="select username, papel from autoridade where username = ?" /> 

     </security:authentication-provider> 

    </security:authentication-manager> 

    <bean 
     class="org.springframework.security.crypto.password.StandardPasswordEncoder" 
     id="passwordEncoder" /> 

</beans> 
package com.test.util; 

import java.io.IOException; 
import java.io.PrintWriter; 

import javax.servlet.ServletException; 
import javax.servlet.http.HttpServletRequest; 
import javax.servlet.http.HttpServletResponse; 

import org.springframework.security.core.AuthenticationException; 
import org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint; 

public class PlainTextBasicAuthenticationEntryPoint extends 
     BasicAuthenticationEntryPoint { 

     @Override 
     public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException { 
      response.addHeader("Access-Control-Allow-Origin", "null"); 
      response.addHeader("WWW-Authenticate", "Basic realm=\"" + getRealmName() + "\""); 
      response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); 
      PrintWriter writer = response.getWriter(); 
      writer.println("HTTP Status " + HttpServletResponse.SC_UNAUTHORIZED + " - " + authException.getMessage()); 
     } 

} 

我的HTTP現在響應:

HTTP/1.1 401 Unauthorized 
Server: Apache-Coyote/1.1 
Access-Control-Allow-Origin: null 
WWW-Authenticate: Basic realm="test.com" 
Content-Length: 35 
Date: Mon, 20 May 2013 20:05:03 GMT 

HTTP Status 401 - Bad credentials 

變更前,我得到這個錯誤信息:

OPTIONS http://localhost:8080/test/customer/name 200 (OK) jquery-1.8.2.min.js:2 
XMLHttpRequest cannot load http://localhost:8080/test/customer/name. Origin null is  not allowed by Access-Control-Allow-Origin. 

現在如我所料,我得到了這一個:

OPTIONS http://localhost:8080/test/customer/name 200 (OK) jquery-1.8.2.min.js:2 
POST http://localhost:8080/test/customer/name 401 (Unauthorized) 
+0

謝謝你。您的解決方案幫助 –

+0

嗨,我想問你以下。我想知道是否有特定的東西來啓用CROSS請求+基本授權+ Spring Security。到目前爲止,我已經完成了設置Tomcat過濾器(我向頭添加授權)所需的一切,因爲它在沒有認證的情況下工作,所以我在ajax中執行我的請求,所以我想知道spring安全是否不會引起問題.....也許你有一些關於它的輸入 – MaatDeamon

+0

Access-Control-Allow-Origin是前端地址。你可以設置「*」來允許所有。 – raonirenosto

相關問題