I have a spring boot application with WebSecurityConfigurerAdapter configured like this -
http.csrf().disable()
.exceptionHandling()
.authenticationEntryPoint(restAuthenticationEntryPoint)
.and()
.authorizeRequests()
.antMatchers("/user/*", "/habbit/*").authenticated()
.and()
.formLogin()
.loginProcessingUrl("/login")
.permitAll()
.usernameParameter("email")
.passwordParameter("pass")
.successHandler(authenticationSuccessHandler)
.failureHandler(new SimpleUrlAuthenticationFailureHandler())
.and()
.logout()
.logoutUrl("/logout")
.invalidateHttpSession(true);
Can I add something like my own controller that would, after successful authentication, return back a custom object with some details about the authenticated user?
Update: To clarity, i'm using an angular application as the client. Currently I need to make 2 requests form my client to the server: 1. POST request to /login URL for authentication. 2. GET request to retrieve authenticated user data.
My aim is to have the 1st request return to me user information so I don't have to make the 2dn request. Currently the 1st request only authenticates the user, creates a session on the server and send back a '200 OK' status response with no data. I want it to return a success response with data about the logged in user.
Answered:
The correct answer is in comments so i will write it here: I needed to redirect from my successHandler to my controller which in turn returns the currently logged in user info ( in my case controller is in url '/user/me':
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
Authentication authentication) throws ServletException, IOException {
clearAuthenticationAttributes(request);
getRedirectStrategy().sendRedirect(request, response, "/user/me");
}
The HttpServletRequest.getUserPrincipal() will return the result of SecurityContextHolder.getContext().getAuthentication() . This means it is an Authentication which is typically an instance of UsernamePasswordAuthenticationToken when using username and password based authentication.
If I understand your problem right, I can suggest next way.
First of all you have to implement class, that will contain user information. This class must be inherited from org.springframework.security.core.userdetails.User:
public class CustomUserDetails extends User {
public CustomUserDetails(String username, String password,
Collection<? extends GrantedAuthority> authorities) {
super(username, password, authorities);
}
//for example lets add some person data
private String firstName;
private String lastName;
//getters and setters
}
Next step, you have create you own implementation of interface org.springframework.security.core.userdetails.UserDetailsService:
@Service
public class CustomUserDetailService implements UserDetailsService{
@Override
public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException{
if(StringUtils.isEmpty(userName))
throw new UsernameNotFoundException("User name is empty");
//if you don't use authority based security, just add empty set
Set<GrantedAuthority> authorities = new HashSet<>();
CustomUserDetails userDetails = new CustomUserDetails(userName, "", authorities);
//here you can load user's data from DB or from
//any other source and do:
//userDetails.setFirstName(firstName);
//userDetails.setLastName(lastName);
return userDetails;
}
}
As you see, this class has just one method, where you can load and set custom user details. Note, that I marked this class with @Service annotation. But you can register it in your Java-config or XML context.
Now, to access your user data after successful authentication, you can use next approach, when Spring will automatically pass principal in controller's method:
@Controller
public class MyController{
@RequestMapping("/mapping")
public String myMethod(Principal principal, ModelMap model){
CustomUserDetails userDetails = (CustomUserDetails)principal;
model.addAttribute("firstName", userDetails.getFirstName());
model.addAttribute("lastName", userDetails.getLastName());
}
}
Or another one way:
@Controller
public class MyController{
@RequestMapping("/mapping")
public String myMethod(ModelMap model){
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
CustomUserDetails userDetails = (CustomUserDetails)auth.getPrincipal();
model.addAttribute("firstName", userDetails.getFirstName());
model.addAttribute("lastName", userDetails.getLastName());
}
}
This method can be used in other places, where Spring does not pass principal automatically.
To go to specific address after successful authentication you can use SimpleUrlAuthenticationSuccessHandler. Just create it in your config:
@Bean
public SavedRequestAwareAuthenticationSuccessHandler successHandler() {
SavedRequestAwareAuthenticationSuccessHandler successHandler = new SavedRequestAwareAuthenticationSuccessHandler();
successHandler.setTargetUrlParameter("/succeslogin");
return successHandler;
}
and use it in your configuration:
http.formLogin()
.loginProcessingUrl("/login")
.permitAll()
.usernameParameter("email")
.passwordParameter("pass")
.successHandler(successHandler())
after that you can create controller, that will send response from speciafied url:
@Controller
@RequestMapping("/sucesslogin")
public class SuccessLoginController{
@RequestMapping(method = RequestMethod.POST)
public String index(ModelMap model, Principal principal){
//here you can return view with response
}
}
Of cause, you can return not only view, but JSON response (using @ResponseBody annotation), or something else, depends on you front-end.
Hope this will be helpful.
In the accepted answer you need two calls to get the data you want. Simply return the data after the login in a custom AjaxAuthenticationSuccessHandler like this.
@Bean
public AjaxAuthenticationSuccessHandler ajaxAuthenticationSuccessHandler() {
return new AjaxAuthenticationSuccessHandler() {
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
response.getWriter().write(new ObjectMapper().writeValueAsString(new UserAuthenticationResponse(authentication.getName(), 123l)));
response.setStatus(200);
}
};
}
and register the successhandler:
http.successHandler(ajaxAuthenticationSuccessHandler())
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With