I have the following controller for logout I want to get the name of the logout user how can I acheive this ?
String userName=(String)session.getAttribute("name");
this line not working
Logout Controller
#RequestMapping(value = "/session", method = RequestMethod.DELETE)
public #ResponseBody ResponseEntity<?> logout(HttpSession session){
String userName=(String)session.getAttribute("name");
System.out.println("name: " + userName);
session.invalidate();
return ResponseEntity.ok("user logged out");
}
I do not have currently any Spring projects near me, but as I remember, it could be possible to do it like this:
SecurityContextHolder.getContext().getAuthentication().getPrincipal();
As I said, I'm not sure if it's working. It's been a while since I last used Spring, but let me know if it is.
Try this.
#Component
public class LogoutListener implements
ApplicationListener<SessionDestroyedEvent> {
private static final Logger logger =
LoggerFactory.getLogger(LogoutListener.class);
#Override
public void onApplicationEvent(SessionDestroyedEvent event) {
List<SecurityContext> lstSecurityContext =
event.getSecurityContexts();
UserDetails ud;
for (SecurityContext securityContext : lstSecurityContext)
{
ud = (UserDetails)
securityContext.getAuthentication().getPrincipal();
logger.info("Logout|Session destroyed User: [{}]",
ud.getUsername());
}
}
}
Related
I want to set a session attribute with the name that is send by user. User will first login in. And when he logged in I want that his username will set as session attribute.
What should I do?
This is my controller:
#GetMapping("/login")
public String login() {
return "Login";
}
#PostMapping("/loginCheck")
public String checkLogin(#ModelAttribute("users") Users user) {
if (userService.checkUser(user)) {
return "redirect:/"+user.getUsername()+"/";
} else {
return "Login";
}
}
#PostMapping("/signup")
public ModelAndView createuser(#ModelAttribute("users") Users user) {
if (userService.checkUser(user)) {
return new ModelAndView("Login");
} else {
userService.adduser(user);
return new ModelAndView("Login");
}
}
Now how I set the username as session which I am getting in user.getUsername()?
In SpringMVC you can have the HttpSession injected automatically by adding it as a parameter to your method. So, you login could be something similar to:
#GetMapping("/login")
public String login(#ModelAttribute("users") Users user, HttpSession session)
{
if(userService.authUser(user)) { //Made this method up
session.setAttribute("username", user.getUsername());
view.setViewName("homepage"); //Made up view
}
else{
return new ModelAndView("Login");
}
}
#Autowired
ObjectFactory<HttpSession> httpSessionFactory;
.
.
.
HttpSession session = httpSessionFactory.getObject();
Works good. Thanks to this post.
If you use Spring Security, registered a bean listening for Spring Security's InteractiveAuthenticationSuccessEvent and SessionDestroyedEvent events. These events fire without any explicit configuration in a default Spring Boot environment.
See https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#web.security:
The basic features you get by default in a web application are:
. . .
A DefaultAuthenticationEventPublisher for publishing authentication events.
By handling these events you can add "username" as a session attribute immediately after a user logons and remove that attribute when the security session (security context) is destroyed:
#Component
public class SessionStoreUsernameAuthEventHandler {
#EventListener
public void audit(InteractiveAuthenticationSuccessEvent e) {
getSession().ifPresent(s -> s.setAttribute("username", e.getAuthentication().getName()));
}
#EventListener
public void audit(SessionDestroyedEvent e) {
getSession().ifPresent(s -> s.removeAttribute("username"));
}
private static Optional<HttpServletRequest> getCurrentRequest() {
return Optional.ofNullable(RequestContextHolder.getRequestAttributes())
.filter(ServletRequestAttributes.class::isInstance)
.map(ServletRequestAttributes.class::cast)
.map(ServletRequestAttributes::getRequest);
}
private static Optional<HttpSession> getSession() {
return getCurrentRequest().map(HttpServletRequest::getSession);
}
}
I had one login controller in that I define one session variable, now I want to access that session variable in all my remaining controllers in my application?
this is my login controller code snippet
#RequestMapping(value = "/login", method = RequestMethod.POST,produces = "application/json")
public #ResponseBody Map<String, String> validateUser(#RequestBody String loginParameters,HttpServletRequest request) throws Exception {
try{
HttpSession session=request.getSession();
JSONObject json = new JSONObject(loginParameters.trim());
String un=json.getString("username");
session.setAttribute("username", un);
This is my ProfileController code snippet
#Controller
public class ProfileController {
#RequestMapping(value = "/getUserData", method = RequestMethod.GET,produces = "application/json")
public #ResponseBody Map<String, String> getUser(HttpServletRequest req) throws Exception {
try{
HttpSession session=req.getSession();
String loggedInUser=(String)session.getAttribute("username");
System.out.println("UserName is "+ loggedInUser);
Now I want to access this session variable(username) in my another profile controller. I tried like this but I got null pointer expection in ProfileController.
I found the solution to my requirement.
actually, my requirement is to access the session value from the login controller to profile controller.
So What I did is instead of accessing the session variable in profile controller, just I am calling a method in login controller that will return my required value.
#Controller
public class LoginController {
private HttpSession session=null;
#RequestMapping(value = "/login", method = RequestMethod.POST,produces = "application/json")
public #ResponseBody Map<String, String> validateUser(#RequestBody String loginParameters,HttpServletRequest request) throws Exception {
try{
session=request.getSession();
JSONObject json = new JSONObject(loginParameters.trim());
String un=json.getString("username");
session.setAttribute("username", un);
}catch(Exception e)
{
}
}
public String getUserName()
{
return session.getAttribute("username");
}
}
ProfileController
#Controller
public class ProfileController {
#Autowired
private LoginController loginControllerObj;
#RequestMapping(value = "/getUserData", method = RequestMethod.GET,produces = "application/json")
public #ResponseBody Map<String, String> getUser(HttpServletRequest req) throws Exception {
try{
String loggedInUser=loginControllerObj.getUserName();
System.out.println("UserName is "+ loggedInUser);
As per my understanding, in my question. I got null pointer exception in Profile controller this is because of if we want to access the session then we need to call the request.getSession()
the method that will return if any session is associated with the request then it will return that one if not then it creates a new session.the same concept in my profile controller also applied.
Instead of accessing the existing session in will create the new session because of both are two different requests.
For this reason, I follow the above code get rid of my requirement.
if it is about current logged in username then you just pass Principal parameter to controller method.
#RequestMapping(value="/login", method = RequestMethod.GET)
public String methodName(ModelMap model, Principal principal ) {
String name = principal.getName(); //get logged in username
model.addAttribute("username", name);
return "page";
}
I want to get the user role after logout button is clicked.
if the role is admin i have to return /login.jsp in /logout
if the role is user i have to return /index.jsp in /logout
Thanks in advance
my controller.java:
#RequestMapping(value="/logout",method=RequestMethod.GET)
public String logout(HttpServletRequest request,ModelMap model)
{
model.addAttribute("userForms",userService.getActiveUserList());
model.addAttribute("Success",true);
return "/login";
}
UserService.java
public List<UserForm> getActiveUserList()
{
List<UserForm> userForms = new ArrayList<UserForm>();
List<User> users = new ArrayList<User>();
users = userDAO.getActiveList();
for (User user : users) {
String crmDomainLink=crmProperties.getProperty("CRMAppDomain");
UserForm userForm = new UserForm(
user.getUserId(),user.getName(), user.getCode(),
CRMConstants.convertUSAFormatWithTime(user.getCreatedDateTime()),
user.getIsEnabled(), null);
userForms.add(userForm);
}
return userForms;
}
MyDAO.java
public List<User> getActiveList() {
return this.sessionFactory.getCurrentSession().createCriteria(User.class).add(Restrictions.and(Restrictions.eq("isEnabled", 1),Restrictions.ne("userId", 1))).list();
}
You should implement a custom LogoutSuccessHandler. Something like:
#Component
public class CustomLogoutSuccessHandler implements LogoutSuccessHandler {
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
if (AuthorityUtils.authorityListToSet(authentication.getAuthorities()).contains("ROLE_ADMIN")) {
response.sendRedirect("/login.jsp");
} else {
response.sendRedirect("/index.jsp");
}
}
}
Add it to security config, if XML:
<logout success-handler-ref="customLogoutSuccessHandler" />
You can get Authentication object in controller by following
#RequestMapping(value="/logout", method = RequestMethod.GET)
public String logout(ModelMap model, Authentication authentication) {
}
Then you can get the roles of logged in user by calling the following method
authentication.getAuthorities();
I have a #RestController with bunch of Rest endpoints as methods.
#RequestMapping(path="",method=RequestMethod.POST)
public void create(Principal principal) {
String userName = principal.getName();
User user = UsersRepository.loadUser(userName);
//....
}
#RequestMapping(path="/{groupId}",method=RequestMethod.DELETE)
public void deleteGroup(#PathVariable String groupId, Principal principal) {
String userName = principal.getName();
User user = UsersRepository.loadUser(userName);
//....
}
In each method I have to repeat this code:
String userName = principal.getName();
User user = UsersRepository.loadUser(userName);
Is there a way not to repeat this in each method and get it in the class, and consume it in each method ?
1) Very basic but why not simply extract it in a private method :
public User getUser(Principal principal){
String userName = principal.getName();
User user = UsersRepository.loadUser(userName);
//....
return user;
}
You could write so :
#RequestMapping(path="",method=RequestMethod.POST)
public void create(Principal principal) {
User user = getUser(principal);
//....
}
2) More advanced : you could use a Spring interceptor that reads in the request, loads the user and wires it in a bean with a request scope.
I have to test this;
/** Displays the balance us page. */
#RequestMapping(value = "/profile/balance")
public ModelAndView balance(Principal principal) {
ModelAndView model = new ModelAndView("balance");
String username = principal.getName();
User user = userService.findUserByUsername(username);
model.addObject("moneyEarned", user.getMoneyEarned());
model.addObject("moneySpent", user.getMoneySpent());
return model;
}
my test looks like that;
#Test
public void getProfileBalance() throws Exception {
this.mockMvc.perform(get("/profile/balance")
.andExpect(status().isOk())
.andExpect(view().name("balance"));
}
I really don't understand how I could pass in that Principal instance.
How can I do that?
Easiest way is by doing
#Test
public void getProfileBalance() throws Exception {
SecurityContext ctx = new SecurityContextImpl();
ctx.setAuthentication(new UsernamePasswordAuthenticationToken("principal", "password"));
SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_GLOBAL);
SecurityContextHolder.setContext(ctx);
this.mockMvc.perform(get("/profile/balance")
.andExpect(status().isOk())
.andExpect(view().name("balance"));
SecurityContextHolder.clearContext();
}
Or you can use the Spring Security Test library