简体   繁体   English

无法在 Angular 5 应用程序中读取授权标头以响应 Spring Boot

[英]Not able to read authorization header in response of spring boot in angular 5 application

I am getting my hands dirty by building an application using the spring framework and Angular 5.我通过使用 spring 框架和 Angular 5 构建应用程序来弄脏我的手。

I have the backend of the application ready using spring boot, spring rest and spring security.我已经使用 spring boot、spring rest 和 spring security 准备好应用程序的后端。 For the purpose of this application, I have used spring JWT tokens for the purpose of authorization.出于此应用程序的目的,我使用 spring JWT 令牌进行授权。

I have tested the backend services using postman and they are working fine without any glitch.我已经使用邮递员测试了后端服务,它们运行良好,没有任何故障。

Now when I try to integrate the application to the front end (Angular 5), I have been facing CORS issue as well as I am unable to access the response headers in in the service calls happening from the front end angular application.现在,当我尝试将应用程序集成到前端(Angular 5)时,我一直面临 CORS 问题,而且我无法访问前端 Angular 应用程序发生的服务调用中的响应标头。

I have already set CORS to Expose headers in response in WebSecurity file.我已经在 WebSecurity 文件中将 CORS 设置为公开标头以响应。

I am able to see in the response a token carrying the Authorization token in Chrome, but still unable to access.我能够在响应中看到带有 Chrome 中授权令牌的令牌,但仍然无法访问。

Any help would be appreciated.任何帮助,将不胜感激。

Thanks!谢谢!

Can anyone suggest what should be the right way to set the CORS in the spring boot application.谁能建议在 spring boot 应用程序中设置 CORS 的正确方法。 My current application looks as below.我当前的应用程序如下所示。

User.java用户.java

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;


@Entity
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;

    private String username;

    private String password;

    public long getId() {
        return id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

}

UserController.java用户控制器.java

import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

import com.app.mycompany.TasksApp.model.User;
import com.app.mycompany.TasksApp.repository.UserRepository;

@RestController
@RequestMapping("/users")
public class UserController {

    private UserRepository userRepository;

    private BCryptPasswordEncoder bCryptPasswordEncoder;

    public UserController(UserRepository userRepository,
                          BCryptPasswordEncoder bCryptPasswordEncoder) {

        this.userRepository = userRepository;
        this.bCryptPasswordEncoder = bCryptPasswordEncoder;
    }

    @PostMapping("/sign-up")
    public void signUp(@RequestBody User user) {
        user.setPassword(bCryptPasswordEncoder.encode(user.getPassword()));
        userRepository.save(user);
    }

}

UserRepository.java用户资料库.java

import org.springframework.data.jpa.repository.JpaRepository;

import com.app.mycompany.TasksApp.model.User;

public interface UserRepository extends JpaRepository<User, Long> {
    User findByUsername(String username);
}

UserDetailsServiceImpl.java UserDetailsServiceImpl.java

import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;

import com.app.mycompany.TasksApp.model.User;
import com.app.mycompany.TasksApp.repository.UserRepository;
import org.springframework.stereotype.Service;

import static java.util.Collections.emptyList;


@Service
public class UserDetailsServiceImpl implements UserDetailsService {

    private UserRepository userRepository;

    public UserDetailsServiceImpl(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        User user = userRepository.findByUsername(username);
        if (user == null) {
            throw new UsernameNotFoundException(username);
        }
        return new org.springframework.security.core.userdetails.User(user.getUsername(), user.getPassword(), emptyList());
    }

}

WebSecurity.java WebSecurity.java

import org.springframework.context.annotation.Bean;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.servlet.config.annotation.CorsRegistry;

import static com.app.mycompany.TasksApp.security.SecurityConstants.SIGN_UP_URL;

import java.util.Arrays;

@EnableWebSecurity
public class WebSecurity extends WebSecurityConfigurerAdapter {

    private UserDetailsService userDetailsService;
    private BCryptPasswordEncoder bCryptPasswordEncoder;
    public WebSecurity(UserDetailsService userDetailsService, BCryptPasswordEncoder bCryptPasswordEncoder) {
        this.userDetailsService = userDetailsService;
        this.bCryptPasswordEncoder = bCryptPasswordEncoder;
    }
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable().authorizeRequests()
                .antMatchers(HttpMethod.POST, SIGN_UP_URL).permitAll()
                .anyRequest().authenticated()
                .antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
                .and().cors().and()
                .addFilter(new JWTAuthenticationFilter(authenticationManager()))
                .addFilter(new JWTAuthorizationFilter(authenticationManager()));
    }

    @Bean
    CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration configuration = new CorsConfiguration();
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();

        configuration.setAllowedOrigins(Arrays.asList("*"));
        configuration.setAllowedHeaders(Arrays.asList("*"));
        configuration.setAllowedMethods(Arrays.asList("GET","POST", "OPTIONS", "PUT", "DELETE"));
        configuration.setAllowCredentials(true);
        configuration.setExposedHeaders(Arrays.asList("Content-type","Authorization"));
        source.registerCorsConfiguration("/**", configuration);
        return source;
    }

    @Override
    public void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder);
    }

}

JWTAuthenticationFilter.java JWTAuthenticationFilter.java

import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;

import com.app.mycompany.TasksApp.model.User;
import com.fasterxml.jackson.databind.ObjectMapper;

import static com.app.mycompany.TasksApp.security.SecurityConstants.EXPIRATION_TIME;
import static com.app.mycompany.TasksApp.security.SecurityConstants.HEADER_STRING;
import static com.app.mycompany.TasksApp.security.SecurityConstants.SECRET;
import static com.app.mycompany.TasksApp.security.SecurityConstants.TOKEN_PREFIX;

import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;

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

public class JWTAuthenticationFilter extends UsernamePasswordAuthenticationFilter {

    private AuthenticationManager authenticationManager;

    public JWTAuthenticationFilter(AuthenticationManager authenticationManager) {
        this.authenticationManager = authenticationManager;
    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest req,
                                                HttpServletResponse res) throws AuthenticationException {
        try {
            User creds = new ObjectMapper()
                    .readValue(req.getInputStream(), User.class);
            return authenticationManager.authenticate(
                    new UsernamePasswordAuthenticationToken(
                            creds.getUsername(),
                            creds.getPassword(),
                            new ArrayList<>())
            );
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    protected void successfulAuthentication(HttpServletRequest req,
                                            HttpServletResponse res,
                                            FilterChain chain,
                                            Authentication auth) throws IOException, ServletException {
        String token = Jwts.builder()
                .setSubject(((org.springframework.security.core.userdetails.User) auth.getPrincipal()).getUsername())
                .setExpiration(new Date(System.currentTimeMillis() + EXPIRATION_TIME))
                .signWith(SignatureAlgorithm.HS512, SECRET)
                .compact();
        res.addHeader(HEADER_STRING, TOKEN_PREFIX + token);
    }

}

JWTAuthorizationFilter.java JWTAuthorizationFilter.java

import java.io.IOException;
import java.util.ArrayList;

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

import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;

import io.jsonwebtoken.Jwts;

import static com.app.mycompany.TasksApp.security.SecurityConstants.EXPIRATION_TIME;
import static com.app.mycompany.TasksApp.security.SecurityConstants.HEADER_STRING;
import static com.app.mycompany.TasksApp.security.SecurityConstants.SECRET;
import static com.app.mycompany.TasksApp.security.SecurityConstants.TOKEN_PREFIX;

public class JWTAuthorizationFilter extends BasicAuthenticationFilter {

    public JWTAuthorizationFilter(AuthenticationManager authManager) {
        super(authManager);
    }

    @Override
    protected void doFilterInternal(HttpServletRequest req,
                                    HttpServletResponse res,
                                    FilterChain chain) throws IOException, ServletException {
        String header = req.getHeader(HEADER_STRING);
        if (header == null || !header.startsWith(TOKEN_PREFIX)) {
            chain.doFilter(req, res);
            return;
        }
        UsernamePasswordAuthenticationToken authentication = getAuthentication(req);
        SecurityContextHolder.getContext().setAuthentication(authentication);
        chain.doFilter(req, res);
    }

    private UsernamePasswordAuthenticationToken getAuthentication(HttpServletRequest request) {
        String token = request.getHeader(HEADER_STRING);
        if (token != null) {
            // parse the token.
            String user = Jwts.parser()
                    .setSigningKey(SECRET)
                    .parseClaimsJws(token.replace(TOKEN_PREFIX, ""))
                    .getBody()
                    .getSubject();
            if (user != null) {
                return new UsernamePasswordAuthenticationToken(user, null, new ArrayList<>());
            }
            return null;
        }
        return null;
    }

}

Angular UI Service call Angular UI 服务调用

I have changed the api to use the HttpClient method as well and observe the response.我已将 api 更改为也使用 HttpClient 方法并观察响应。 Still I am unable to access the headers in response.我仍然无法访问标头作为响应。

authenticate(credentials, callback) {

    const AuthorizationHeader = credentials ? 'Basic ' + btoa(credentials.username + ':' + credentials.password) : '';

    const serviceheaders = new HttpHeaders({'Content-Type': 'application/json', 'Authorization' : AuthorizationHeader});

    // const headers = new HttpHeaders({
    //   'Content-Type': 'application/json', 'Authorization' : AuthorizationHeader
    // });

    const username = credentials ? credentials.username : '';
    const password = credentials ? credentials.password : '';

    this.http.post<HttpResponse<any>>('http://localhost:8080/login', JSON.stringify({username: username, password: password})
          , {headers: serviceheaders, observe: 'response', responseType: 'json'})
                  .subscribe( (response: HttpResponse<any>) => {
                    console.log('Headers only: ' + response.headers);
                    console.log('Response Headers : ' + response.headers.get('Authorization'));
                    const token = response.headers.get('Authorization');
                    if (token !== null) {
                      this.authenticated = true;
                    }
                    return callback && callback();
    });

  }

I know I'm late but I had a similar problem with React + Spring Boot.我知道我迟到了,但我在使用 React + Spring Boot 时遇到了类似的问题。 It was solved by adding "config.setExposedHeaders(Arrays.asList("Authorization"))" in my CORS configuration:通过在我的 CORS 配置中添加“config.setExposedHeaders(Arrays.asList("Authorization"))”解决了这个问题:

@Bean
CorsConfigurationSource corsConfigurationSource() {

    final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    CorsConfiguration config = new CorsConfiguration();
    source.registerCorsConfiguration("/**", config.applyPermitDefaultValues());
    config.setExposedHeaders(Arrays.asList("Authorization"));

    return source;
}

In my frontend I did the following:在我的前端,我做了以下事情:

export default function ({ history }) {
   const [login, setLogin] = useState('');
   const [password, setpassword] = useState('');

   async function handleLogin(e) {
       e.preventDefault();

       const response = await Api.post('/login', {
           login, senha: password
       });

       console.log(response.headers);
       if(response.headers['authorization']){
           history.push("/menu");
       }
}

As you can see, the "Authorization" header comes in lower case.如您所见,“授权”标头采用小写形式。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 后端Angular 2 + Spring Boot中未收到授权标头 - Authorization header is not receiving in the backend Angular 2 + Spring Boot 无法从 API 响应(Spring Boot Service)读取 Angular 中的 cookies(正在读取)- 无法读取 Z37A6259CC0C1DAE299A 的属性(正在读取) - Not able to read cookies in Angular from API response (Spring Boot Service) - Cannot read properties of null (reading 'headers') 无法在Spring Boot Application提供的响应中设置&#39;Access-Control-Allow-Origin&#39;标头 - Not able to set 'Access-Control-Allow-Origin' header in the response provided by Spring Boot Application 无法在Express中读取Angular 2 http标头授权令牌 - Not able to read Angular 2 http header Authorization token in Express Angular2 Spring Boot JWT 缺少响应头 - Angular2 Spring Boot JWT missing Response Header Spring Boot CORS配置不接受授权标头 - Spring Boot CORS configuration is not accepting authorization header Spring Boot + Angular 应用程序 - Spring Boot + Angular Application 从使用 Angular 7 的请求接收 Spring Boot 中的 null Authorization 标头,但 Postman 工作正常 - Receiving null Authorization header in Spring Boot from requests with Angular 7 but Postman works fine 没有授权头从Angular发送POST到Spring - No Authorization Header sending POST from Angular to Spring 无法读取 angular 中的响应 header - cannot read a response header in angular
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM