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);
}
}
Related
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());
}
}
}
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 an spring mvc web application in which users login to session "session.setAttribute" classically. Whenever I need loggedin user data I use this data.
Now I want to add android app and what I want to learn do I have to add additional methods for each android request and send user data within it?
Or Is there away to make a request to same methods.
What is the consept for this kind of cloud apps? Do I have to write different methods for android requests? Because it is not possible session.getAttribute when wemake an android request, it returns null.
User user = userService.getByUserNameAndPassword(userName, password);
if (user != null) {
if (user.isActive()) {
Account account = new Account(user, request.getRemoteAddr());
HttpSession httpSession = request.getSession(true);
AccountRegistry.add(httpSession);
httpSession.setAttribute(Constant.ACCOUNT, account);
result.put(Constant.REF, Constant.SUCCESS);
}
public class Account {
private UserRightsHandler userRightsService = null;
private User user;
private String ipAddress;
private boolean admin;
public Account(User user, String ipAddress) {
this.user = user;
this.ipAddress = ipAddress;
userRightsService = new UserRightsHandler(user);
setAdmin(userRightsService.isAdmin());
}
public UserRightsHandler getUserRightsService() {
return userRightsService;
}
public User getUser() {
return this.user;
}
public String getIpAddress() {
return ipAddress;
}
public boolean isAdmin() {
return admin;
}
private void setAdmin(boolean admin) {
this.admin = admin;
}
}
public class AccountRegistry {
private static final Map<String, HttpSession> sessions = new HashMap<String, HttpSession>();
public static void add(HttpSession session) {
sessions.put(session.getId(), session);
}
public static void remove(HttpSession session) {
if (session != null) {
sessions.remove(session.getId());
session.setAttribute(Constant.ACCOUNT, null);
session.invalidate();
}
}
public static HttpSession getByHttpSessionID(String httpSessionID) {
Set<String> keys = sessions.keySet();
Iterator it = keys.iterator();
while (it.hasNext()) {
String sID = (String) it.next();
HttpSession session = sessions.get(sID);
if (sID.equals(httpSessionID)) {
return session;
}
}
return null;
}
public static void removeByHttpSessionID(String httpSessionID) {
HttpSession session = getByHttpSessionID(httpSessionID);
remove(session);
}
public static Account getCurrentAccount() {
HttpServletRequest request = ContextFilter.getCurrentInstance().getRequest();
HttpSession session = request.getSession();
return (Account) session.getAttribute(Constant.ACCOUNT);
}
}
#RequestMapping(value = "/changeStatus", method = RequestMethod.POST)
public #ResponseBody
String changeStatus(HttpServletRequest request, HttpServletResponse response) throws UnsupportedEncodingException {
User editor = AccountRegistry.getCurrentAccount().getUser();
}
You can ask user send their user and password at the start of Android app via custom authenticate request like /appLogin then if it is correct creditentals you can return a key to user (to app) and store it to some variable during app run. Then when user want to do something send a request to server you can send it to a function with mapping like /appExampleService then you can check at that function this key and device valid depending on how you handle custom login process then this function call existing function that is used for web browsers that have mapping /exampleService. For example;
#JsonSerialize
#RequestMapping("/appExampleService")
public int someServiceForAppClient(
#RequestParam(value = "key", required = true) String apikey,
#RequestParam(value = "param", required = true) String someParam{
String name=userDAO.getUsernameFromApiKey(apikey);
return someService(someParam, name);
}
#JsonSerialize
#RequestMapping("/exampleService")
public int someServiceForWebClient(
#RequestParam(value = "param", required = true) String someParam) {
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
String name = auth.getName();
return someService(someParam, name);
}
public int someService(String someParam,String name){
return doBusiness(someParam, name);
}
userDAO is just something I created for to get info of user with given key. And there is a service for App login as well which return that key to user when he started the app send his username and pass
I have spring(4.0.6) web application. I've noticed that when user logon then logout and try to logon once again gets an error about user\pass.
I don't have web.xml file because I am using SpringBootServletInitializer class to config my application.
I've add to my configuration such bean
#Bean
public ServletListenerRegistrationBean<HttpSessionEventPublisher> httpSessionEventPublisher()
{
return new ServletListenerRegistrationBean<HttpSessionEventPublisher>(new HttpSessionEventPublisher());
}
and in security config I have this:
http.sessionManagement()
.maximumSessions(1).expiredUrl("/login?expired")
.maxSessionsPreventsLogin(true)
.and()
.sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
.invalidSessionUrl("/");
As I understand previous session is alive and because of Maximum session = 1 user can't login once again. What should I do to avoid it?
You should invalidate the user session when he logout. Below is the piece of code. Need to pass the userid.
UserInfo is the POJO
public boolean invalidateUserSession(Long userId) {
List<Object> principalsList = sessionRegistry.getAllPrincipals();
Object targetPrincipal = null;
for (Object principal : principalsList) {
if (principal instanceof UserInfo) {
if (((UserInfo) principal).getId().equals(userId)) {
targetPrincipal = principal;
break;
}
}
}
if (targetPrincipal == null) {
return false;
}
List<SessionInformation> userSessionsList = sessionRegistry.getAllSessions(targetPrincipal, false);
for (SessionInformation x : userSessionsList) {
x.expireNow();
}
return true;
}
I have a managed bean LoginBean:
#ManagedBean(name = "loginBean")
#SessionScoped
public class LoginBean implements Serializable {
private String email, password;
private BasicUser user;
/** Creates a new instance of LoginBean */
public LoginBean() {
}
public void setUser(BasicUser user) {
this.user = user;
}
public BasicUser getUser() {
return user;
}
...
}
And then a PhaseListener who gets the sessions loginBean.
public class FacebookSignInListener implements PhaseListener, UserService {
private LoginBean bean;
....
#Override
public PhaseId getPhaseId() {
return PhaseId.RENDER_RESPONSE;
}
#Override
public void afterPhase(PhaseEvent event) {
HttpSession session = (HttpSession) event.getFacesContext().getExternalContext().getSession(true);
bean = (LoginBean) session.getAttribute("loginBean");
bean.setUser(facebookUser);
}
#Override
public void beforePhase(PhaseEvent event) {
FacesContext fc = FacesContext.getCurrentInstance();
request = (HttpServletRequest) fc.getExternalContext().getRequest();
boolean isLoginPage =
(fc.getViewRoot().getViewId().indexOf("welcome") > -1);
if (isLoginPage) {
try {
FBOauth fbo = new FBOauth(this);
fbo.doLogin(request);
} catch (IOException ex) {
Logger.getLogger(FacebookSignInListener.class.getName()).log(Level.SEVERE, "Could not exchange code for access_token. Page where not found.", ex);
}
}
}
#Override
public boolean authFacebookLogin(String accessToken, FacesContext fc) throws FacebookException {
if (accessToken != null) {
FacebookClient facebookClient = new DefaultFacebookClient(accessToken);
User fbUser = facebookClient.fetchObject("me", User.class);
UserHelper uh = new UserHelper();
FacebookUser facebookUser = (FacebookUser) uh.getByFacebookId(fbUser.getId());
// Does the user already exist and is he already connected with facebook.
if (facebookUser != null) {
return true;
}
}
}
}
When I after deploy on the admin console press launch application, logs into my application via facebook there is no problem with the code below. I can logout and log in again and still no problem. If I then change browser and tries to login via facebook here I get a NullPointerException where I do
bean.setUser(facebookUser)
This also happens if I close the first browser, opens again and tries to login via facebook. Why is this happening?
I am using Glassfish v3.
If the session scoped bean is null then it simply means that it hasn't been created for the session yet. This can happen during the very first request of a fresh session. You've to create it yourself and put it in the session scope yourself. JSF will just reuse it in the remnant of the session.
Your way of grabbing the session scoped bean is a bit clumsy. You're getting the raw Servlet API from under the JSF's hoods. You could also just use ExternalContext#getSessionMap() to manage the session attributes.
Map<String, Object> sessionMap = externalContext.getSessionMap();
LoginBean loginBean = (LoginBean) sessionMap.get("loginBean");
if (loginBean == null) {
loginBean = new LoginBean();
sessionMap.put("loginBean", loginBean);
}
// ...
Note that you shouldn't declare the bean as an instance variable of the PhaseListener. There is namely a single PhaseListener instance throughout the application's lifetime, so all instance variables would be shared among all requests/sessions. In other words: it's not threadsafe.
Seems like you are trying to use the bean before it was created since your PhaseListener is firing in the first Phase. Have you tried to shift it to a later phase?
Edit:
You access the session with the crate flag set to true:
HttpSession session = (HttpSession) externalContext.getSession(true);
Thus, your newly created session wont include any session scoped beans.
The Framework will instantiate the session scoped Bean and put in the session object when an expression referencing the bean is evaluated, which is not the case here.