My React app is just a simple login Page and my intention is how do I able to tackle the Spring Security Authentication via React Login,
My React app is running at localhost:5713
My Spring app is running at localhost:5001
my react code:
export default function Login(){
let [username,setUsername]=useState('')
let [password,setPassword]=useState('')
let formSubmit=async(e)=>{
e.preventDefault();
console.log(username,password)
const login=await fetch("http://localhost:5001/login",{
method: 'POST',
headers:{
'Content-Type':'application/json'
},
body:JSON.stringify({username,password})
})
console.log(login)
const data=login.json();
console.log(data)
}
// useEffect(()=>{
// },[])
return(
<>
<form onSubmit={formSubmit}>
<label htmlFor="username">Name</label>
<input id="username" name="username" type="text" value={username} onChange={e=>setUsername(e.target.value)} />
<label htmlFor="password">Password</label>
<input id="password" name="password" value={password} onChange={e=>setPassword(e.target.value)} type="password" />
{/* <button type="submit">Login</button> */}
<Button>Submit</Button> <!-- my custom button Component -->
</form>
</>
)
}
and here is how my Spring Boot Security looks like:
@EnableWebSecurity
public class SecurityConfigTest implements WebMvcConfigurer {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.securityMatcher("/**")
.authorizeHttpRequests(authorize -> authorize
.requestMatchers("/user/add", "/csrf", "/login").permitAll()
.anyRequest().authenticated()
)
.formLogin(formLogin -> formLogin
.loginPage("http://localhost:5173/login") // My react app Login Form
.defaultSuccessURL("/testing") //its defined in my Springboot controller
)
return http.build();
}
@Bean
UserDetailsService userDetailsService(PasswordEncoder pa) {
UserDetails user=User.withUsername("admin")
.password(pa.encode("pass"))
.roles("ADMIN")
.build();
System.out.println("at userDetailsService");
UserDetails user1=User.withUsername("user")
.password(pa.encode("user"))
.roles("USER")
.build();
System.out.println(user.getUsername());
System.out.println(user.getPassword());
return new InMemoryUserDetailsManager(user,user1);
}
}
I was using the @CrossOrigin(origins = "http://localhost:5173") into my spring boot app at my Controller Class level.
My Controller:
@Controller
@CrossOrigin(origins = "http://localhost:5173")
class ConnTest{
UserRepo userRepo;
@Autowired
TestingSerivce test;
// one way to read the app.props values
@Value("${spring.jpa.database}")
String dbname;
ConnTest(UserRepo userRepo,TestingSerivce test){
this.userRepo=userRepo;
this.test=test;
}
@ResponseBody
@GetMapping("/")
String test(HttpServletRequest req) {
return "Hello Welcome to my Demo";
}
@ResponseBody
@PostMapping("/user/add")
int addUser(@RequestBody User user) {
userRepo.save(user);
System.out.println(user);
return 1;
}
@ResponseBody
@GetMapping("/out")
String logoutHere(HttpServletRequest req) throws ServletException {
System.out.println(req.getRemoteUser()+"nSession : "+req.getSession());
req.logout();
HttpSession session = req.getSession(false);
if(session!=null) session.invalidate();
System.out.println(req.getRemoteUser()+"nSession : "+req.getSession());
return "Logging out...";
}
@ResponseBody
@GetMapping("/csrf")
CsrfToken httpServReq(HttpServletRequest req) {
// return securityConfig.csrfToken(req);
System.out.println("tesing");
return (CsrfToken) req.getAttribute("_csrf");
}
@ResponseBody
@GetMapping("/test/x")
String testx(@RequestParam(required = false) String msg) {
String header="{'ab':'xyx'}";
byte []b=header.getBytes();
String encoded=Base64.getEncoder().encodeToString(b);
System.out.println(encoded);
if (msg == null) {
return "Null Msg";
}
return "this is my Testingx -> " + msg;
}
@ResponseBody
@PostMapping("/login")
UserDetails userLogin(@RequestBody UserDetail user) {
System.out.println(user.getUsername()+" -- "+user.getPassword());
return user;
}
}
Issue:
I’m getting my React login form successfully whenever I try to access any secure route defined in Spring Controller (don’t no its good to use it like it) but whenever I provide the credentials and hit Submit button I’m getting the Cors Error even I mentioned it at Controller Class level.
Also Unable to redirect to secureRoutes
When I try the same with unsecured URLs Cors is working total fine without any issues. So I believe issue is only when working with secure routes.
Also I see that authentication is done by Postman app normally but unable to authenticate via react app. When correct username and passwords are passed via react its working normally but when I pass the wrong credentials I’m getting error (which is only on google console when checking from react side and its normal) but Still I’m treated as unauthenticated and not allowed to access any secure routes. I’m not getting where did I went wrong.
Is there any mistake done by me when using Spring Security Authentication?
Access to fetch at 'http://localhost:5001/login' from origin 'http://localhost:5173' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
Login.jsx:14
POST http://localhost:5001/login net::ERR_FAILED
formSubmit @ Login.jsx:14
callCallback2 @ react-dom.development.js:4164
invokeGuardedCallbackDev @ react-dom.development.js:4213
invokeGuardedCallback @ react-dom.development.js:4277
invokeGuardedCallbackAndCatchFirstError @ react-dom.development.js:4291
executeDispatch @ react-dom.development.js:9041
processDispatchQueueItemsInOrder @ react-dom.development.js:9073
processDispatchQueue @ react-dom.development.js:9086
dispatchEventsForPlugins @ react-dom.development.js:9097
(anonymous) @ react-dom.development.js:9288
batchedUpdates$1 @ react-dom.development.js:26179
batchedUpdates @ react-dom.development.js:3991
dispatchEventForPluginEventSystem @ react-dom.development.js:9287
dispatchEventWithEnableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay @ react-dom.development.js:6465
dispatchEvent @ react-dom.development.js:6457
dispatchDiscreteEvent @ react-dom.development.js:6430
Show 15 more frames
Show less
Login.jsx:14
Uncaught (in promise) TypeError: Failed to fetch
at formSubmit (Login.jsx:14:27)
at HTMLUnknownElement.callCallback2
2
Answers
You have to enable
CORS policy
in your Springboot application. You can do it by using:-Refer this answer for more context: – origin has been blocked by CORS policy Spring boot and React