You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

已登录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:

  1. You're updating currentLoginuser.setPresent(false) but not handling the session concurrency control properly (your config enforces max-sessions="1")
  2. 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

  1. Inject CustomUserDetailsService: Make sure to autowire your CustomUserDetailsService in the controller instead of instantiating it manually:

    @Autowired
    private CustomUserDetailsService customUserDetailsService;
    
  2. Verify Session Concurrency: Your existing session-management config with max-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 CustomUserDetailsService to load the target user's permissions, ensuring access control checks pass
  • The UsernamePasswordAuthenticationToken is 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 09:23:58