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