I'm creating an user API and trying to implement an authentication method through Spring Boot security.
Even using the correct password and the default Spring Security user user
, my Postman still gives me an authorization error. I can't see where the problem is in this code.
Security config:
package com.api.business_products_management.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.web.SecurityFilterChain;
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated()
.and()
.httpBasic();
return http.build();
}
}
Controller:
package com.api.business_products_management.controllers;
import com.api.business_products_management.dtos.UserDto;
import com.api.business_products_management.models.UserModel;
import com.api.business_products_management.services.UserService;
import jakarta.validation.Valid;
import org.springframework.beans.BeanUtils;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.web.bind.annotation.*;
@RestController
@CrossOrigin(origins = "*", maxAge = 3600)
@RequestMapping("/user")
public class UserController {
private BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
final UserService userService;
public UserController(UserService userService) {
this.userService = userService;
}
@PostMapping
public ResponseEntity<Object> saveUser(@RequestBody @Valid UserDto userDto) {
var userModel = new UserModel();
BeanUtils.copyProperties(userDto, userModel);
userModel.setPassword(passwordEncoder().encode(userModel.getPassword()));
return ResponseEntity.status(HttpStatus.CREATED).body(userService.save(userModel));
}
}
Console:
2023-02-17T18:24:13.152-03:00 INFO 8418 --- [nio-8099-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet'
2023-02-17T18:24:13.152-03:00 INFO 8418 --- [nio-8099-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
2023-02-17T18:24:13.154-03:00 INFO 8418 --- [nio-8099-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 1 ms
Without seeing your Postman request, my initial guess would be that it's the lack of CSRF (from your Postman request) which is causing the 401. You can read more about CSRF within Spring here: https://docs.spring.io/spring-security/site/docs/5.0.x/reference/html/csrf.html
From that document:
As of Spring Security 4.0, CSRF protection is enabled by default
You can test this theory by temporarily disabling CSRF as shown in the example configuration here:
https://docs.spring.io/spring-security/site/docs/5.0.x/reference/html/csrf.html#csrf-configure
i.e.:
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.anyRequest().authenticated()
.and()
.httpBasic();
return http.build();
}
}
I'd highly recommend reading the rest of the documentation to familiarize yourself with what CSRF protects against and whether it's an acceptable risk to turn it off (or selectively turn disable for certain paths) prior to disabling it in a production environment though.