[英]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.