2013-05-17 18 views
8

Mam problem związany z nagłówkiem odpowiedzi HTTP "Access-Control-Allow-Origin" podczas korzystania z podstawowego uwierzytelniania ze sprężyną. Kiedy uwierzytelniać ręcznie, jak mieszka kodu (używam REST):Spring Security, REST podstawowy problem uwierzytelniania

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

wszystko działa poprawnie, otrzymuję następującą odpowiedź 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 

jak widać, „Access- Control-Allow-Origin "jest obecny w odpowiedzi. Wszystko jest w porządku tutaj. Mogę złapać błąd 401 w moim wywołaniu ajax.

Ale gdy autoryzacja odbywa się automatycznie, jak w kodzie poniżej:

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

odpowiedź 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 

Nie ma "Access-Control-Allow-Origin" w odpowiedź

Konsola Google Chrome wyświetla następujący błąd:

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

Moje wywołanie ajax nie zwraca 401 nieautoryzowanego błędu, mimo że odpowiedź HTTP go zwraca (odpowiedź powyżej), otrzymuję nieznany błąd.

Doszedłem do wniosku, że dla wszystkich przeglądarek potrzebuję "Access-Control-Allow-Origin" w odpowiedzi HTTP, w przeciwnym razie wygenerują jakiś cichy błąd i moje połączenie ajaxowe zawiedzie (nie może złapać Błąd 401). Właściwie javascript nie powiedzie się po cichu. XMLHttpRequest nie przyjmuje odpowiedzi HTTP bez "Access-Control-Allow-Origin".

Co mogę zrobić, aby Spring wstrzyknął to "Kontrola dostępu-pozwól-Origin" w odpowiedziach HTTP dla podstawowego uwierzytelnienia?

to mój xml Wiosna Bezpieczeństwo:

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

Odpowiedz

11

Wystarczy znaleźć swój własny sposób:

Przede wszystkim, ja naprawdę nie pamiętam dlaczego kładę tę linię, ale to był brudząc mój kod:

<security:http-basic /> 

Po drugie, ta odpowiedź pokazuje mi ścieżkę: Handle unauthorized error message for Basic Authentication in Spring Security. Musiałem stworzyć niestandardowy punkt wejścia do uwierzytelniania, aby wysłać obiekt Access-Control-Allow-Origin.

Więc to jest mój kod teraz:

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

} 

Moja http odpowiedź teraz:

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 

przed zmianą, dostałem ten komunikat o błędzie:

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. 

a teraz zgodnie z oczekiwaniami otrzymuję ten:

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

dzięki człowiekowi. Twoje rozwiązanie pomogło. –

+0

Witam, chciałbym Cię zapytać, co następuje. Chciałbym wiedzieć, czy jest coś konkretnego, aby umożliwić CROSS Request + Basic Authorization + Spring Security. Do tej pory zrobiłem wszystko, co konieczne, aby ustawić filtr Tomcat (dodałem autoryzację do nagłówków), wykonuję moją prośbę w ajaxu tak, jak powinno, biorąc pod uwagę, że działa bez uwierzytelnienia, więc zastanawiam się, czy bezpieczeństwo wiosny nie powoduje problemu ..... Może masz trochę informacji na ten temat? – MaatDeamon

+0

Access-Control-Allow-Origin to adres front-end. Możesz ustawić "*", aby pozwolić wszystkim. – raonirenosto

Powiązane problemy