I precise that I am a french student in 1st year of Java Developper.
I’m developing a little multi-module app using: Spring Boot, Spring security, Hibernate, Spring Data, Spring MVC and Thymeleaf.
I would like to set the User in the session, or at least the userId, at login. This way I don’t have to put it manually in the session or in the model each time I need it.
But as I use the default Spring Security login and authentication configuration, I really don’t know how or where to call such a method:
void putUserInHttpSession( HttpSession httpSession ) { httpSession.setAttribute( "user" , getManagerFactory().getUserManager().findByUserName( SecurityContextHolder.getContext().getAuthentication().getName()) ); }
I can do it eahc time I need it but I find it pretty ugly not to just do this at login in!
Here are what I think you might need to help me (that would be AWESOME !!! 🙂
My WebSecurityConfig class:
@Configuration public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private UserDetailsServiceImpl userDetailsService; @Autowired private DataSource dataSource; @Bean public BCryptPasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } @Autowired public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { // Setting Service to find User in the database. // And Setting PassswordEncoder auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder()); } @Override protected void configure( HttpSecurity http ) throws Exception { http.csrf().disable(); // /userInfo page requires login as ROLE_USER or ROLE_ADMIN. // If no login, it will redirect to /login page. http.authorizeRequests().antMatchers( "/user/**") .access("hasAnyRole('ROLE_USER', 'ROLE_ADMIN')"); // For ADMIN only. http.authorizeRequests().antMatchers( "/admin/**") .access("hasRole('ROLE_ADMIN')"); // When the user has logged in as XX. // But access a page that requires role YY, // AccessDeniedException will be thrown. http.authorizeRequests().and().exceptionHandling().accessDeniedPage("/public/403"); // Config for Login Form http.authorizeRequests().and().formLogin()// // Submit URL of login page. .loginProcessingUrl("/j_spring_security_check") // Submit URL .loginPage("/public/login").defaultSuccessUrl("/public/showAtlas")// .failureUrl("/public/login?error=true")// .usernameParameter("username")// .passwordParameter("password") //Config for Logout Page .and() .logout().logoutUrl("/public/logout").logoutSuccessUrl("/public/logoutSuccessful"); http.authorizeRequests().antMatchers( "/public/**").permitAll(); // The pages does not require login } }
My UserDetailsServiceImpl class:
@Service public class UserDetailsServiceImpl implements UserDetailsService{ @Autowired private ManagerFactory managerFactory; // private HttpSession httpSession; /** * The authentication method uses the user email, since it is easier to remember for most users * @param input * @return a UserDetails object * @throws UsernameNotFoundException */ @Override public UserDetails loadUserByUsername( String input) throws UsernameNotFoundException { User user = new User(); if( input.contains( "@" )){ user = this.managerFactory.getUserManager().findByEmail( input ); } else { user = this.managerFactory.getUserManager().findByUserName( input ); } if (user == null) { throw new UsernameNotFoundException( "User with email " + input + " was not found in the database" ); } // [ROLE_USER, ROLE_ADMIN,..] List<String> roleNames = this.managerFactory.getRoleManager().findRoleByUserName(user.getUserName()); List<GrantedAuthority> grantList = new ArrayList<GrantedAuthority>(); if (roleNames != null) { for (String role : roleNames) { // ROLE_USER, ROLE_ADMIN,.. GrantedAuthority authority = new SimpleGrantedAuthority(role); grantList.add(authority); } } return (UserDetails) new org.springframework.security.core.userdetails.User(user.getUserName(), user.getPassword(), grantList); } }
My simple LoginController:
@Controller public class LoginController{ @GetMapping("/public/login") public String login(Model model ){ return "view/login"; } @GetMapping("/public/logoutSuccessful") public String logout(Model model) { return "view/logoutSuccessful"; }
So, is there a simple way to put the user or userId in the httpSession at login?
Thank you very much guys!!!
THE SOLUTION
Create a CustomAuthenticationSuccessHandler
@Component public class CustomAuthenticationSuccessHandler implements AuthenticationSuccessHandler { @Autowired private ManagerFactory managerFactory; @Override public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException { String userName = ""; HttpSession session = request.getSession(); Collection< GrantedAuthority > authorities = null; if(authentication.getPrincipal() instanceof Principal ) { userName = ((Principal)authentication.getPrincipal()).getName(); session.setAttribute("role", "none"); }else { User userSpringSecu = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); session.setAttribute("role", String.valueOf( userSpringSecu.getAuthorities())); session.setAttribute( "connectedUser" , managerFactory.getUserManager().findByUserName( userSpringSecu.getUsername() ) ); } response.sendRedirect("/public/showAtlas" ); } }
Then Autowired this class and add it in the WebSecurityConfigurerAdapter
@Configuration public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private UserDetailsServiceImpl userDetailsService; @Autowired private CustomAuthenticationSuccessHandler customAuthenticationSuccessHandler; @Autowired private DataSource dataSource; @Bean public BCryptPasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } @Autowired public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { // Setting Service to find User in the database. // And Setting PassswordEncoder auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder()); } @Override protected void configure( HttpSecurity http ) throws Exception { http.csrf().disable(); // /userInfo page requires login as ROLE_USER or ROLE_ADMIN. // If no login, it will redirect to /login page. http.authorizeRequests().antMatchers( "/user/**") .access("hasAnyRole('ROLE_USER', 'ROLE_ADMIN')"); // For ADMIN only. http.authorizeRequests().antMatchers( "/admin/**") .access("hasRole('ROLE_ADMIN')"); // http.exceptionHandling().accessDeniedPage( "/error/403" ); // When the user has logged in as XX. // But access a page that requires role YY, // AccessDeniedException will be thrown. http.authorizeRequests().and().exceptionHandling().accessDeniedPage("/public/403"); // Config for Login Form http.authorizeRequests().and().formLogin()// // Submit URL of login page. .loginProcessingUrl("/j_spring_security_check") // Submit URL .loginPage("/public/login") .defaultSuccessUrl("/public/showAtlas")// .successHandler( customAuthenticationSuccessHandler ) .failureUrl("/public/login?error=true")// .usernameParameter("username")// .passwordParameter("password") //Config for Logout Page .and() .logout().logoutUrl("/public/logout").logoutSuccessUrl("/public/logoutSuccessful"); http.authorizeRequests().antMatchers( "/public/**").permitAll(); // The pages does not require login } }
Advertisement
Answer
Assuming you wanted to add user to session on seccessful login, You can create the AuthenticationSuccessHandler
like below and register using successHandler(new AuthenticationSuccessHandlerImpl())
Update:
If we create the object AuthenticationSuccessHandlerImpl
, it will not be spring mananged and hence autowire
into your Securityconfig
and use it like shown below.
Here autowire the AuthenticationSuccessHandler
in your WebSecurityConfig
@Autowired AuthenticationSuccessHandler authenticationSuccessHandler;
and use it WebSecurityConfig.java
@Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .antMatchers("/resources/**", "/registration").permitAll() .anyRequest().authenticated() .and() .formLogin() .loginPage("/login") .permitAll().successHandler(authenticationSuccessHandler) // See here .and() .logout() .permitAll(); }
The AuthenticationSuccessHandlerImpl.java
import java.io.IOException; import java.security.Principal; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.Authentication; import org.springframework.security.core.userdetails.User; import org.springframework.security.web.authentication.AuthenticationSuccessHandler; import org.springframework.stereotype.Component; import com.techdisqus.auth.repository.UserRepository; @Component public class AuthenticationSuccessHandlerImpl implements AuthenticationSuccessHandler{ @Autowired HttpSession session; //autowiring session @Autowired UserRepository repository; //autowire the user repo private static final Logger logger = LoggerFactory.getLogger(AuthenticationSuccessHandlerImpl.class); @Override public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException { // TODO Auto-generated method stub String userName = ""; if(authentication.getPrincipal() instanceof Principal) { userName = ((Principal)authentication.getPrincipal()).getName(); }else { userName = ((User)authentication.getPrincipal()).getUsername(); } logger.info("userName: " + userName); //HttpSession session = request.getSession(); session.setAttribute("userId", userName); } }
Hope this helps.