已登录User角色,无表单切换Employee角色认证失败排查请求
Hey there, let's dive into why your role switch from User to Employee isn't working and fix it step by step.
Core Issues in Your Current Logic
The main problem with your switchAccount method is that you're manually creating an unauthenticated UsernamePasswordAuthenticationToken and shoving it into the SecurityContext. Spring Security doesn't recognize this as a valid authentication because:
- It lacks the user's granted authorities (permissions), which are required for access control checks
- It hasn't gone through Spring Security's official authentication flow (so no validation or session syncing happens)
Additionally, there are two secondary issues:
- You're updating
currentLoginuser.setPresent(false)but not handling the session concurrency control properly (your config enforcesmax-sessions="1") - You're using the encrypted password from the database to create the token, which conflicts with Spring Security's password encoder logic
Fixed switchAccount Method
Here's the revised code that addresses all these problems. We'll skip password validation (since the user is already authenticated) and properly set up the authenticated token with permissions:
@RequestMapping(value = "/switch-account", method = RequestMethod.GET) public String switchAccount(HttpServletRequest request, HttpServletResponse response, Principal principal) { LOG.info("Entry::switchAccount"); HttpSession session = request.getSession(); String userId = (String) session.getAttribute("userId"); NormalUser normalUserObj = socialNetworkingService.findUserById(userId); // Step 1: Clean up the current session and security context SecurityContextHolder.clearContext(); session.invalidate(); // This handles the max-sessions=1 constraint // Step 2: Fetch the target Employee user from DB User userObj = userDao.findById(normalUserObj.getWorkingEmailId()); try { // Step 3: Load the UserDetails (includes permissions) using your custom service UserDetails targetUserDetails = customUserDetailsService.loadUserByUsername(userObj.getUsername()); // Step 4: Create a fully authenticated token with authorities Authentication authenticatedAuth = new UsernamePasswordAuthenticationToken( targetUserDetails, null, // Skip password check since we trust the switch request targetUserDetails.getAuthorities() ); // Step 5: Set the authenticated token to SecurityContext SecurityContextHolder.getContext().setAuthentication(authenticatedAuth); // Step 6: Create a new session and populate necessary attributes HttpSession newSession = request.getSession(true); newSession.setMaxInactiveInterval(-1); // Repopulate session attributes for the Employee role WorkingPlace work = workingPlaceDao.findByUserName(userObj.getUsername()); NormalUser empUser = socialNetworkingService.findUserById(work.getId()); Company company = companyService.findById(work.getCompanyId()); newSession.setAttribute("username", empUser.getEmail()); newSession.setAttribute("userId", empUser.getUserId()); newSession.setAttribute("name", SocialNetworkingUtil.camelCase(empUser.getName())); newSession.setAttribute("workingpalce", work); newSession.setAttribute("orgType", SocialNetworkingUtil.SELECTED_ORGNIZATION_TYPE.PRIVATE.toString().toLowerCase()); newSession.setAttribute("orgId", company.getId()); } catch (UsernameNotFoundException | AuthenticationException e) { LOG.error("Failed to switch to employee account: ", e); return "redirect:/home"; // Fallback to original page if switch fails } LOG.info("Exit::switchAccount"); return "redirect:/welcome"; }
Additional Configuration Tweaks
Inject CustomUserDetailsService: Make sure to autowire your
CustomUserDetailsServicein the controller instead of instantiating it manually:@Autowired private CustomUserDetailsService customUserDetailsService;Verify Session Concurrency: Your existing
session-managementconfig withmax-sessions="1"is correct, but invalidating the old session (as done in Step 1) is critical to avoid "session expired" errors when switching.
Why This Works
- We use your existing
CustomUserDetailsServiceto load the target user's permissions, ensuring access control checks pass - The
UsernamePasswordAuthenticationTokenis marked as authenticated by passing the authorities list - We properly clean up the old session to comply with your concurrency rules
- We skip password validation because the user is already logged in (we trust the switch request)
内容的提问来源于stack exchange,提问作者Laxmi Prajapati

