I want to implement is to send a request from Postman to json, and go through spring security authentication, and receive the user’s id in json format on the response body in Postman
I looked up… UsernamePasswordAuthenticationToken is handled based on a form login, but I want to request it as json, I have to make a custom authentication filter, is that right?
So I implemented it because I heard that I had to implement a custom authentication filter and also successful and failure handler
And I sent a request from Postman, but doesn’t show up in the response body. also shows 403 forbidden
enter image description here
Please give me some advice…thank you
personal question
-
If I implement a custom authentication filter, is there anything that the controller has to implement? Then, do I implement a success failure handler?
For example, usingSecurityContextHolder.getContext().setAuthentication()
on the controller -
If the developer implements a custom authentication filter, should the authentication manager and provider also implement it?
my code start
SecurityConfig
@Configuration
@EnableWebSecurity
public class SecurityConfig {
private final CustomUserDetailService customUserDetailService;
private final ObjectMapper objectMapper;
@Autowired
public SecurityConfig(CustomUserDetailService customUserDetailService, ObjectMapper objectMapper) {
this.customUserDetailService = customUserDetailService;
this.objectMapper = objectMapper;
}
@Bean
public WebSecurityCustomizer configure() {
return (web -> web.ignoring()
.requestMatchers("/search/**")
.requestMatchers("/login/signUp/**")
);
}
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.csrf(AbstractHttpConfigurer::disable)
.httpBasic(AbstractHttpConfigurer::disable)
.formLogin(AbstractHttpConfigurer::disable)
// .addFilterAfter(jsonAuthenticationFilter(), LogoutFilter.class)
.addFilterAt(jsonAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class)
.sessionManagement(sessionManagementConfigurer
-> sessionManagementConfigurer.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.authorizeHttpRequests(authz -> authz
.requestMatchers("/secured/login").permitAll()
.anyRequest().authenticated()
);
return http.build();
}
@Bean
public AuthenticationManager authenticationManager() throws Exception {
DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider();
daoAuthenticationProvider.setUserDetailsService(customUserDetailService);
daoAuthenticationProvider.setPasswordEncoder(passwordEncoder());
return new ProviderManager(daoAuthenticationProvider);
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public JsonAuthenticationFilter jsonAuthenticationFilter() throws Exception {
JsonAuthenticationFilter jsonAuthenticationFilter = new JsonAuthenticationFilter(objectMapper);
jsonAuthenticationFilter.setAuthenticationManager(authenticationManager());
jsonAuthenticationFilter.setAuthenticationSuccessHandler(JsonLoginSuccessHandler());
return jsonAuthenticationFilter;
}
@Bean
public JsonLoginSuccessHandler JsonLoginSuccessHandler() {
return new JsonLoginSuccessHandler();
}
}
JsonAuthenticationFilter
public class JsonAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
private static final String DEFAULT_LOGIN_REQUEST_URL = "/secured/login";
private static final String HTTP_METHOD = "POST";
private static final String CONTENT_TYPE = "application/json";
private static final String USERNAME_KEY = "id";
private static final String PASSWORD_KEY = "password";
private static final AntPathRequestMatcher DEFAULT_LOGIN_PATH_REQUEST_MATCHER = new AntPathRequestMatcher(DEFAULT_LOGIN_REQUEST_URL, HTTP_METHOD);
private final ObjectMapper objectMapper;
public JsonAuthenticationFilter(ObjectMapper objectMapper) {
super(DEFAULT_LOGIN_PATH_REQUEST_MATCHER);
this.objectMapper = objectMapper;
}
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException {
if(request.getContentType() == null || !request.getContentType().equals(CONTENT_TYPE)) {
throw new AuthenticationServiceException("Authentication Content-Type not supported: " + request.getContentType());
}
ServletInputStream inputStream = request.getInputStream();
String messageBody = StreamUtils.copyToString(inputStream, StandardCharsets.UTF_8);
Map<String, String> parseJsonToMap = objectMapper.readValue(messageBody, Map.class);
String username = parseJsonToMap.get(USERNAME_KEY);
String password = parseJsonToMap.get(PASSWORD_KEY);
UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(username, password);
return super.getAuthenticationManager().authenticate(usernamePasswordAuthenticationToken);
}
}
JsonLoginSuccessHandler
public class JsonLoginSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
UserPrincipal principal = (UserPrincipal) authentication.getPrincipal();
ObjectMapper objectMapper = new ObjectMapper();
String jsonPrincipal = objectMapper.writeValueAsString(principal);
System.out.println("jsonPrincipal = " + jsonPrincipal);
response.setContentType("application/json");
response.setCharacterEncoding("UTF-8");
response.getWriter().write(jsonPrincipal);
}
}
CustomUserDetailService
@Service
public class CustomUserDetailService implements UserDetailsService {
private final UserRepository userRepository;
@Autowired
public CustomUserDetailService(UserRepository userRepository) {
this.userRepository = userRepository;
}
@Override
public UserDetails loadUserByUsername(String username) {
User user = userRepository.findByUserId(username)
.orElseThrow(() -> new UsernameNotFoundException("Not found User"));
return UserPrincipal.builder()
.id(user.getUserId())
.password(user.getUserPassword())
.authorities(List.of(new SimpleGrantedAuthority("ROLE_USER"))) // Collections.singleton()
.build();
}
}
UserPrincipal
@Getter
@Builder
@AllArgsConstructor
public class UserPrincipal implements UserDetails {
private final String id;
private final String password;
private final Collection<? extends GrantedAuthority> authorities;
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return authorities;
}
@Override
public String getPassword() {
return password;
}
@Override
public String getUsername() {
return id;
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
}
LoginController
```@PostMapping(value = "/secured/login")
public String login(@AuthenticationPrincipal UserDetails userDetails) {
return userDetails.getUsername();
}
```
user24997409 is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.