13
respostas

Angular e servidor

Vou abrir o mesmo tópico que este https://cursos.alura.com.br/forum/topico-angular-e-servidor-57845.

Devo ter feito algo de errado, pois voltou a dar o erro.

Criei esta classe:

package br.com.netsoft.configuracao.auth;

import java.io.IOException;

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

import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

@Component
public class CrossOriginFilter extends OncePerRequestFilter {

    @Override
    protected void doFilterInternal(HttpServletRequest request,
            HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {
        final String origin = "http://localhost:4200";
        response.addHeader("Access-Control-Allow-Origin", origin);
        response.setHeader("Access-Control-Allow-Methods",
                "POST, PUT, GET, DELETE, OPTIONS");
        response.setHeader("Access-Control-Allow-Credentials", "true");
        response.setHeader(
                "Access-Control-Allow-Headers",
                "Authorization, Origin, X-Requested-With, Content-Type, Accept,"
                        + "x-gwt-module-base, x-gwt-permutation, clientid, longpush");
        filterChain.doFilter(request, response);
    }
}

Na configuração do spring

    @Bean
    public FilterRegistrationBean corsFilterRegistration() {
        FilterRegistrationBean registrationBean = new FilterRegistrationBean(
                new CrossOriginFilter());
        registrationBean.setName("CORS Filter");
        registrationBean.addUrlPatterns("/*");
        registrationBean.setOrder(1);
        return registrationBean;
    }

Só que não funciona, sempre dá erro 401, o que pode ser ?

13 respostas

O que aparece no console do navegador? Aparece algo relativo ao cors? Pergunto pq 401 é de autorização... e pode ser que o cors esteja correto, mas a configuração do spring security tenha alguma falha.

Console do navegador.

Requisição cross-origin bloqueada: A política de mesma origem (Same Origin Policy) impede a leitura do recurso remoto em http://localhost:8080/des-if-web/admin/paisRecurso/pesquisar. (Motivo: o cabeçalho CORS 'Access-Control-Allow-Origin' não está presente).

spring security

package br.com.netsoft.configuracao.auth;

import java.util.Arrays;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private JwtAuthenticationEntryPoint unauthorizedHandler;

    @Autowired
    private JwtTokenUtil jwtTokenUtil;

    @Autowired
    private JwtUserDetailsService jwtUserDetailsService;

    @Value("${jwt.header}")
    private String tokenHeader;

    @Value("${jwt.route.authentication.path}")
    private String authenticationPath;

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth)
            throws Exception {
        auth.userDetailsService(jwtUserDetailsService).passwordEncoder(
                passwordEncoderBean());
    }

    @Bean
    public PasswordEncoder passwordEncoderBean() {
        return new BCryptPasswordEncoder();
    }

    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception {
        httpSecurity
                .csrf()
                .disable()

                .exceptionHandling()
                .authenticationEntryPoint(unauthorizedHandler)
                .and()

                .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()

                .authorizeRequests()

                .antMatchers("/login/**")
                .permitAll()
                .antMatchers("/admin/**")
                .access("hasRole('ROLE_DES_IF_ADMINIST')").anyRequest()
                .authenticated();

        JwtAuthorizationTokenFilter authenticationTokenFilter = new JwtAuthorizationTokenFilter(
                userDetailsService(), jwtTokenUtil, tokenHeader);
        httpSecurity.addFilterBefore(authenticationTokenFilter,
                UsernamePasswordAuthenticationFilter.class);

        httpSecurity.headers().frameOptions().sameOrigin() 
                .cacheControl();
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring()
                .antMatchers(HttpMethod.POST, authenticationPath)
                .and()
                .ignoring()
                .antMatchers(HttpMethod.GET, "/", "/*.html", "/favicon.ico",
                        "/**/*.html", "/**/*.css", "/**/*.js");
    }

    @Bean
    public CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration configuration = new CorsConfiguration();
        configuration.setAllowedOrigins(Arrays.asList("http://localhost:4200"));
        configuration.setAllowedMethods(Arrays.asList("GET", "POST", "OPTIONS",
                "PUT"));
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/admin/**", configuration);
        return source;
    }
}

Opa, realmente o erro é de cors :P. Bom, não vi nada de errado no seu filtro. Tem que debugar... O seu filtro está sendo chamado? Pelo erro parece que não, mas tem que garantir.

Um outro jeito de fazer é adicionar a annotation @CrossOrigin em cima do controller específico...

Coloco um breakpoint na linha CorsConfiguration configuration = new CorsConfiguration();. Só para nesta linha quando inicio o servidor.

Ao chamar este controller http://localhost:8080/des-if-web/admin/paisRecurso/pesquisar, não chama.

o controller está assim:

@CrossOrigin(origins = "http://localhost:4200") @GetMapping(value = "/paisRecurso/pesquisar", produces = MediaType.APPLICATION_JSON_UTF8_VALUE) public ResponseEntity<?> buscarTodos() {

Não chega nem no controller.

Acho que o problema está aqui:

String requestHeader = request.getHeader("Authorization");

Se preencho a variável requestHeader com um token válido, funciona.

Debugando

Navegador

Servidor

Ninguém ?

Opa Guilherme, acho que não entendi aqui. Se você descobriu que o problema está no preenchimento do token, pq não fazer isso?

Caso o problema esteja no primeiro request, o que vai gerar a autorização, eu acho que ele não chama seu filtro pq você já está usando a annotation @CrossOrigin. Agora se o CrossOrigin não funcionar, aí realmente eu não sei. Tem algum detalhe específico do seu projeto que não está dando para entender.

O sistema gera o token no JAVA, retorna e guarda no angular.

Agora quando ele gera uma ação de GET ou POST, pelo que entendi ele não leva o valor no header.

Nesta parte request.getHeader("Authorization"); ele não encontra nada.

Acho que descobri o erro, mas ainda não consegui ajustar. Entendeu ?

Opa. Nos locais do angular que você dispara um get ou um post, pq será que não consegue repassar esse token? O trabalho complicado você já fez, que é montar toda estrutura de autenticacao e tal.

Não sei.

As imagens que inclui neste tópico mostra que no cliente navegador, ele existe, mas não sei o porque não está passando para o servidor. Ainda acho que é alguma configuração no servidor, que ainda não foi feito. Antes de chegar nas classes do JWT, que valida o TOKEN.

Tem algum método que consigo ver o que está chegando no header ?

Acho que ele está vindo vazio ou se perdendo.

No angular está assim:

  myHeaders = new Headers({
    'Accept': 'application/json, text/plain, */*',
    'Content-Type': 'application/json',
    'Authorization': 'Bearer ' +  localStorage.getItem('token')
  });
options = new RequestOptions({
    headers: this.myHeaders
  });
getPaises() {
    return this.http.get(this.userUrl + "/pesquisar",  this.options)
      .map((response: Response) => {
        console.log("Pesquisou por todos " + response.status);
       return response.json();
      }).catch((error:any) => Observable.throw(error.json().error || 'Erro em buscar países'));
  }

Pelo que debuguei o options está corretamente preenchido, pelo navegador.

Se está chegando nulo no servidor é porque não está sendo enviado ou está sendo consultado pelo nome errado. O que você pode ver, para garantir que está indo, é olhar no console os dados da requisição que é enviada e barrada. No console do navegador, no header da requisição, deve aparecer o valor do token. Lembrando que é diferente do token que você mostrou, ali ta mostrando as infos de um objeto literal montado pela sua aplicação, mas não necessariamente os dados que estão enviados efetivamente na requisição.

Pelo que entendi e pela imagem, para que o browser não está enviando o token.

Estou correto ?

Além do mais parece que está enviando authorization e não Authorization