Issue
I can't get authfication user from post request method in controller. I am tryed use @AuthficationPrincipal UserDetails, Principal and SecurityContextHolder but his returns null. It's need me for upload images to datebase. Help me solve this problem please. (.csrf disabled)
Controller:
@Controller
@RequestMapping("/images")
public class ImageController {
private final ImageService imageService;
private final UserService userService;
@Autowired
public ImageController(ImageService imageService,
UserService userService) {
this.imageService = imageService;
this.userService = userService;
}
@PostMapping("/load-image")
public String loadImage(@RequestParam("image") MultipartFile image,
@AuthenticationPrincipal UserDetails user){
User authUser = userService.findUserByNickname(user.getUsername());
imageService.load(image, authUser);
return "redirect:/users/show/"+authUser.getId();
}
}
Security config:
@Configuration
@EnableWebSecurity
public class SecurityCFG extends WebSecurityConfigurerAdapter {
private final BCryptPasswordEncoder bCryptPasswordEncoder;
private final MyUserDetailsService userDetailsService;
@Autowired
public SecurityCFG(BCryptPasswordEncoder bCryptPasswordEncoder,
MyUserDetailsService userDetailsService) {
this.bCryptPasswordEncoder = bCryptPasswordEncoder;
this.userDetailsService = userDetailsService;
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.userDetailsService(userDetailsService)
.passwordEncoder(bCryptPasswordEncoder);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.
csrf().disable()
.authorizeRequests()
.antMatchers("/").permitAll()
.antMatchers("/orders/**").authenticated()
.antMatchers("/users/orders").authenticated()
.antMatchers("/admin/**").hasRole("ADMIN")
.and()
.formLogin().loginPage("/users/login")
.usernameParameter("login")
.passwordParameter("password")
.and()
.logout().logoutSuccessUrl("/users/login?logout").permitAll();
}
}
UserDetails Service:
@Service
public class MyUserDetailsService implements UserDetailsService {
private final UserService userService;
@Autowired
public MyUserDetailsService(UserService userService) {
this.userService = userService;
}
@Override
@Transactional
public UserDetails loadUserByUsername(final String login){
User user;
if(login.contains("@")){
user = userService.findUserByEmail(login);
}else{
user = userService.findUserByNickname(login);
}
if(user!=null){
List<GrantedAuthority> authorities = getUserAuthority(user.getRoles());
return buildUserForAuthentication(user, authorities);
}
throw new BadCredentialsException(String.format("Логин %s неверный",login));
}
private List<GrantedAuthority> getUserAuthority(Set<Role> userRoles) {
Set<GrantedAuthority> roles = new HashSet<>();
for (Role role : userRoles) {
roles.add(new SimpleGrantedAuthority(role.getRole()));
}
return new ArrayList<>(roles);
}
private UserDetails buildUserForAuthentication(User user,
List<GrantedAuthority> authorities) {
UserDetails userDetails = new
org.springframework.security.core.userdetails.User(user.getNickname(),
user.getPassword(),user.isActive(), true,true,
user.isAccountNonLocked(), authorities);
new AccountStatusUserDetailsChecker().check(userDetails);
return userDetails;
}
}
Solution
Its because you are using @Controller
and not @RestController
If you want to get your controller to work properly you should be using @RestController
instead of only @Controller
on your rest controller classes. @RestController
is actually a shorthand for @Controller
and @ResponseBody
which basically tells spring that you want to serialize all responses from functions to something like json, or xml etc. etc.
you can read more about the annotation here.
Answered By - Toerktumlare
Answer Checked By - Robin (JavaFixing Admin)