2013-05-17 14 views
8

Ho riscontrato un problema relativo all'intestazione della risposta HTTP "Access-Control-Allow-Origin" quando si utilizza l'autenticazione di base con Spring. Quando ho autenticare manualmente, come il codice qui sotto (sto usando REST):Spring Security, problema di autenticazione di base 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); 
    } 
} 

tutto funziona bene, ho visualizzato il seguente risposta 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 

come si può vedere, "Access- Control-Allow-Origin "è presente sulla risposta. Qui va tutto bene. Posso ricevere un errore 401 nella mia chiamata Ajax.

Ma quando l'autenticazione viene eseguita automaticamente, come il codice sotto:

@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; 
} 

la risposta HTTP è:

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 

Non c'è un "Access-Control-Allow-Origin" nel risposta

Google Chrome consolle mostrano il seguente errore:

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

La mia chiamata ajax non restituisce un errore non autorizzato 401, anche se la risposta HTTP lo restituisce (risposta sopra), ricevo un errore di non conoscenza.

Ho capito che per tutti i browser, ho bisogno di un "Access-Control-Allow-Origin" nella risposta HTTP, altrimenti genereranno qualche tipo di errore silenzioso e la mia chiamata ajax fallirà (non riesco a prendere il Errore 401). In realtà, javascript fallirà silenziosamente. XMLHttpRequest non accetta una risposta HTTP senza "Access-Control-Allow-Origin".

Come posso fare in modo che Spring inietti "Access-Control-Allow-Origin" nelle risposte HTTP per l'autenticazione di base?

questo è il mio xml Primavera di sicurezza:

<?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> 

risposta

11

appena trovato la mia strada:

Prima di tutto, non mi ricordo perché ho messo questa linea qui, ma era incasinare il mio codice:

<security:http-basic /> 

In secondo luogo, questa risposta mi mostra il percorso: Handle unauthorized error message for Basic Authentication in Spring Security. Ho dovuto creare un punto di ingresso per l'autenticazione personalizzata per inviare la cosa Access-Control-Allow-Origin.

Quindi questo è il mio codice ora:

<?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()); 
     } 

} 

La mia risposta http ora:

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 

prima della modifica, ho ricevuto questo messaggio di errore:

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. 

e ora come previsto ottengo questo:

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

grazie uomo. la tua soluzione ha aiutato. –

+0

Ciao, vorrei chiederti quanto segue. Mi piacerebbe sapere se c'è qualcosa di specifico per abilitare CROSS Request + Basic Authorization + Spring Security. Finora ho fatto tutto il necessario per impostare il filtro Tomcat (ho aggiunto l'autorizzazione alle intestazioni), faccio la mia richiesta in ajax come dovrebbe, dato che funziona senza autenticazione, quindi mi chiedo se la sicurezza di primavera non stia causando un problema ..... Forse hai qualche input su di esso – MaatDeamon

+0

Access-Control-Allow-Origin è l'indirizzo di front-end. È possibile impostare "*" per consentire tutti. – raonirenosto

Problemi correlati