2015-06-03 15 views
10

Così ho la seguente autorizzazione del server condensato dal this example da Dave SyerStandalone Primavera OAuth2 JWT Autorizzazione Server + CORS

@SpringBootApplication 
public class AuthserverApplication { 

    public static void main(String[] args) { 
      SpringApplication.run(AuthserverApplication.class, args); 
    } 

    /* added later 
    @Configuration 
    @Order(Ordered.HIGHEST_PRECEDENCE) 
    protected static class MyWebSecurity extends WebSecurityConfigurerAdapter { 

     @Override 
     protected void configure(HttpSecurity http) throws Exception { 
      http //.csrf().disable() 
       .authorizeRequests() 
       .antMatchers(HttpMethod.OPTIONS, "/oauth/token").permitAll(); 
     } 
    }*/ 

    @Configuration 
    @EnableAuthorizationServer 
    protected static class OAuth2AuthorizationConfig extends 
        AuthorizationServerConfigurerAdapter { 

      @Autowired 
      private AuthenticationManager authenticationManager; 

      @Bean 
      public JwtAccessTokenConverter jwtAccessTokenConverter() { 
        JwtAccessTokenConverter converter = new JwtAccessTokenConverter(); 
        KeyPair keyPair = new KeyStoreKeyFactory(
            new ClassPathResource("keystore.jks"), "foobar".toCharArray()) 
            .getKeyPair("test"); 
        converter.setKeyPair(keyPair); 
        return converter; 
      } 

      @Override 
      public void configure(ClientDetailsServiceConfigurer clients) throws Exception { 
        clients.inMemory() 
            .withClient("acme") 
            //.secret("acmesecret") 
            .authorizedGrantTypes(//"authorization_code", "refresh_token", 
                "password").scopes("openid"); 
      } 

      @Override 
      public void configure(AuthorizationServerEndpointsConfigurer endpoints) 
          throws Exception { 
        endpoints.authenticationManager(authenticationManager).accessTokenConverter(
            jwtAccessTokenConverter()); 
      } 

      @Override 
      public void configure(AuthorizationServerSecurityConfigurer oauthServer) 
          throws Exception { 
        oauthServer.tokenKeyAccess("permitAll()").checkTokenAccess(
            "isAuthenticated()"); 
      } 
    } 
} 

quando l'eseguo e testarlo con l'arricciatura

curl [email protected]:8110/oauth/token -d grant_type=password -d client_id=acme -d username=user -d password=password 

ho un JWT come risposta, ma non appena provo ad accedere a AuthServer dal mio frontend (Angular JS su una porta diversa) ottengo l'errore CORS. Non a causa di intestazioni mancanti, ma perché la richiesta OPTION viene rifiutata e mancano le credenziali.

Request URL:http://localhost:8110/oauth/token 
Request Method:OPTIONS 
Status Code:401 Unauthorized 
WWW-Authenticate:Bearer realm="oauth", error="unauthorized", error_description="Full authentication is required to access this resource" 

sapevo già che devo aggiungere un CorsFilter e inoltre trovato this post dove ho usato il frammento per la prima risposta di lasciare l'accesso richiesta OPZIONI /oauth/token senza credenziali:

@Order(-1) 
public class MyWebSecurity extends WebSecurityConfigurerAdapter { 
    @Override 
    protected void configure(HttpSecurity http) throws Exception { 
     http 
      .authorizeRequests() 
      .antMatchers(HttpMethod.OPTIONS, "/oauth/token").permitAll(); 
    } 
} 

Dopo di che ho avuto con l'arricciatura il seguente errore:

{"timestamp":1433370068120,"status":403,"error":"Forbidden","message":"Expected CSRF token not found. Has your session expired?","path":"/oauth/token"} 

Quindi, per rendere le cose semplici ho solo aggiunto http.csrf().disable() al 0.123.metodo della classe MyWebSecurity, che risolve il problema con la richiesta OPTION, ma quindi la richiesta POST non funziona più e ottengo There is no client authentication. Try adding an appropriate authentication filter. (anche con arricciatura).

Ho cercato di scoprire se devo in qualche modo collegare la classe MyWebSecurity e l'AuthServer, ma senza fortuna. L'esempio originale (link all'inizio) inietta anche AuthenticManager, ma questo non ha cambiato nulla per me.

risposta

64

Trovato il motivo del mio problema!

Ho solo bisogno di terminare la filterchain e restituire immediatamente il risultato se una richiesta OPTIONS viene elaborata da CorsFilter!

SimpleCorsFilter.java

@Component 
@Order(Ordered.HIGHEST_PRECEDENCE) 
public class SimpleCorsFilter implements Filter { 

    public SimpleCorsFilter() { 
    } 

    @Override 
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { 
     HttpServletResponse response = (HttpServletResponse) res; 
     HttpServletRequest request = (HttpServletRequest) req; 
     response.setHeader("Access-Control-Allow-Origin", "*"); 
     response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE"); 
     response.setHeader("Access-Control-Max-Age", "3600"); 
     response.setHeader("Access-Control-Allow-Headers", "x-requested-with, authorization"); 

     if ("OPTIONS".equalsIgnoreCase(request.getMethod())) { 
      response.setStatus(HttpServletResponse.SC_OK); 
     } else { 
      chain.doFilter(req, res); 
     } 
    } 

    @Override 
    public void init(FilterConfig filterConfig) { 
    } 

    @Override 
    public void destroy() { 
    } 
} 

Dopo che ho potuto ignorare le opzioni di richiesta di verifica preliminare nella mia authserver = D

Così il server funziona come nel snipped sopra e si può ignorare il commento blocco con MyWebSecurity classe all'inizio

+2

In alternativa, è possibile utilizzare il 'CorsFilter' fornito con Spring Framework 4.2+ e Spring Boot 1.3+, vedere il mio [risposta qui] (http: // StackOverflow.it/a/31748398/1092077) per ulteriori dettagli. –

+2

@ SébastienDeleuze Il CorsFilter di Spring sembra essere eseguito dopo FilterChain per qualche motivo e risulta ancora non autorizzato :( – froginvasion

+1

Hai provato a cambiare l'ordine dei filtri come descritto [qui] (http://stackoverflow.com/a/26147788/1092077)? –

1

beh, hai ragione! questa è una soluzione, e ha funzionato anche per me (ho avuto lo stesso problema)

ma lasciate che sussgest di usare un'implementazione CORS filtro intelligente per Java: http://software.dzhuvinov.com/cors-filter.html

Si tratta di una soluzione molto completa per le applicazioni Java.

In realtà, è possibile vedere here come il tuo punto è stato risolto.

+2

Spring Framework 4.2+ nativo 'CorsFilter' è probabilmente un'alternativa migliore, [vedi questa risposta] (http://stackoverflow.com/a/31748398/1092077) per maggiori dettagli. –

9

Ho trovato una soluzione utilizzando la soluzione per la domanda. Ma ho un altro modo per descrivere la soluzione:

@Configuration 
public class WebSecurityGlobalConfig extends WebSecurityConfigurerAdapter { 
     .... 
     @Override 
     public void configure(WebSecurity web) throws Exception { 
     web.ignoring() 
      .antMatchers(HttpMethod.OPTIONS); 
     } 
     ... 
} 
+0

quale versione stai usando? non sembra avere ".ignoring" nella mia versione di Spring Security. @ Cirillo – XPLOT1ON

+0

E 'stato fatto con Spring 1.5.2-Release. Funziona ancora bene con 1.5.9-Release. – Cyril

Problemi correlati