У меня есть проект весенней загрузки, который использует весеннюю безопасность с токеном JWT. Это отлично работает в POSTMAN, но выдает ошибку 403 при использовании реагирующих аксиом. Ниже приведен код, используемый
SecurityConfig.java
package com.cg.practice.EmployeeCRUD.config;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.BeanIds;
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.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.cors.CorsConfiguration;
import com.cg.practice.EmployeeCRUD.Service.CustomUserService;
import com.cg.practice.EmployeeCRUD.filter.EmployeeCRUDFilter;
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
CustomUserService userService;
@Autowired
EmployeeCRUDFilter employeeCRUDFilter;
/*
* @Autowired CorsFilter corsFilter;
*/
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// TODO Auto-generated method stub
System.out.println("Hi1");
auth.userDetailsService(userService);
}
@Bean
public PasswordEncoder passwordEncoder() {
return NoOpPasswordEncoder.getInstance();
}
@Bean(name = BeanIds.AUTHENTICATION_MANAGER)
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Override
protected void configure(HttpSecurity http) {
// TODO Auto-generated method stub
System.out.println("Hi2");
try {
CorsConfiguration corsConfiguration = new CorsConfiguration();
corsConfiguration.setAllowedHeaders(List.of("Authorization", "Cache-Control", "Content-Type"));
corsConfiguration.setAllowedOrigins(List.of("http://localhost:3000"));
corsConfiguration.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE", "PUT","OPTIONS","PATCH", "DELETE"));
corsConfiguration.setAllowCredentials(true);
corsConfiguration.setExposedHeaders(List.of("Authorization"));
http
// .addFilterBefore(corsFilter, SessionManagementFilter.class)
.csrf().disable().authorizeRequests().antMatchers("/authenticate/")
.permitAll().anyRequest().authenticated()
.and().exceptionHandling().and().sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and().cors().configurationSource(request -> corsConfiguration);
;
http.addFilterBefore(employeeCRUDFilter, UsernamePasswordAuthenticationFilter.class);
}
catch (Exception e)
{
// TODO: handle exception
e.printStackTrace();
}
}
}
СотрудникCRUDFilter.java
package com.cg.practice.EmployeeCRUD.filter;
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.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import com.cg.practice.EmployeeCRUD.Service.CustomUserService;
import com.cg.practice.EmployeeCRUD.util.JwtUtil;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
@Component
public class EmployeeCRUDFilter extends OncePerRequestFilter {
@Autowired
JwtUtil jwtUtil;
@Autowired
CustomUserService userService;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
{
// TODO Auto-generated method stub
String authorizationHeader = request.getHeader("Authorization");
String token = null;
String userName = null;
try
{
if (authorizationHeader != null && authorizationHeader.startsWith("Bearer ")) {
token = authorizationHeader.substring(7);
userName = jwtUtil.extractUsername(token);
}
if (userName != null && SecurityContextHolder.getContext().getAuthentication() == null) {
UserDetails userDetails = userService.loadUserByUsername(userName);
if (jwtUtil.validateToken(token, userDetails)) {
UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken =
new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
usernamePasswordAuthenticationToken
.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
}
}
filterChain.doFilter(request, response);
}
catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
}
Метод CRUDController
@PostMapping("/authenticate")
public String generateToken(@RequestBody AuthRequest authRequest) throws Exception
{
try {
authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(
authRequest.getUserName(),authRequest.getPassword())
);
}
catch (Exception e) {
return "Invalid User/Password";
}
return jwtUtil.generateToken(authRequest.getUserName());
}
Реагировать Authservice.js
import http from '../Mycomponent/http-common';
class AuthService{
authenticate(){
return http.post("/authenticate", {"userName":"Dip","password":"password@123"}
)
.then(response => {
console.info(response.data)
if (response.data.accessToken) {
localStorage.setItem("user", JSON.stringify(response.data));
}
return response.data;
})
.catch(error =>{
console.info("Error :"+error);
});
}
}
export default new AuthService();
http-common.js
import axios from 'axios';
export default axios.create({
baseURL: "http://localhost:8080/CRUD",
headers: {
"Content-type": "application/json"
}
});
Это дает ошибку 403 в браузере
Failed to load resource: the server responded with a status of 403 ()
AuthService.js:16 Error :Error: Request failed with status code 403
:8080/CRUD/getAll:1 Failed to load resource: the server responded with a status of 403 ()
createError.js:16 Uncaught (in promise) Error: Request failed with status code 403
at createError (createError.js:16:1)
at settle (settle.js:17:1)
at XMLHttpRequest.onloadend (xhr.js:66:1)
Кто-нибудь может помочь. Я застрял на нем в течение длительного времени. Я что-то упускаю? Я новичок в реакции.
Отлично работает в PostMAN
authentication(){ return http.post("/authenticate", {"userName":"Dip","password":"password@123"}) Я делаю это для нее. Это какая-то ошибка, которую я делаю?
Запрос к /authenticate
возвращает 403 или запрос к /CRUD
?
В настройках безопасности вы определяете /authenticate
как единственный маршрут с анонимным доступом. Я думаю, что это должно быть /CRUD/authenticate
, если это то, что вы звоните, чтобы войти.
См. базовый URL-адрес, в который включен CRUD. Любая проблема, которую вы видите в CORS на стороне сервера?
Обратите внимание, что Spring Security имеет встроенную поддержку аутентификации JWT, поэтому нет необходимости создавать свою собственную. Вы можете проверить образец здесь.
при использовании почтальона я могу подключиться и получить этот токен jwt, но от реакции я получаю эту ошибку cors
Похоже, вы пропустили Authorization
в заголовке при настройке экземпляра axios.
authentication(){ return http.post("/authenticate", {"userName":"Dip","password":"password@123"}) Я делаю это с ней. Это какая-то ошибка, которую я делаю? - Не могли бы вы показать пример, что вы имеете в виду
для аутентификации первого запроса я генерирую токен jwt, поэтому требуется ли авторизация?
Я думаю здесь кроется проблема:
http
.csrf().disable().authorizeRequests().antMatchers("/authenticate/")
.permitAll().anyRequest().authenticated()
.and().exceptionHandling().and().sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and().cors().configurationSource(request -> corsConfiguration);
Вы сообщаете spring о запросах permitAll
к конечной точке /authenticate/
и требуете аутентификации для всех остальных запросов. Но из внешнего интерфейса вы делаете запрос к /CRUD/authenticate/
. Вот почему вы получаете 403, потому что этот путь должен быть аутентифицирован — это означает, что запрос уже должен иметь заголовок Authorization
. Я думаю, что это должно работать, если вы измените первую строку на это:
.csrf().disable().authorizeRequests().antMatchers("/CRUD/authenticate/")
В бэкэнде Spring Boot он формирует URL-адрес, как в файле application.properties. У меня есть server.servlet.contextPath=/CRUD, который формирует URL-адрес как localhost:8080/CRUD/authenticate.
Я понимаю. Как насчет завершающей косой черты в antMatcher. Это должно быть там?
Да, я пропустил косую черту в ответе. Он должен быть в антматчере.
Похоже, вы не отправляете какие-либо учетные данные с запросом axios. Разве вы не должны устанавливать заголовок авторизации? Или вы используете какое-то промежуточное ПО, которое должно это делать?