HttpServletRequest request.getSession().setAttribute 不起作用

时间:2021-03-01 13:59:16

标签: java spring-boot spring-data-redis httpsession spring-session

我正在使用 RedisHttpSession,我的基本目标是在成功登录时将人员对象保存在会话对象中,在需要的任何地方检索它并在注销时销毁会话。

成功登录后,这就是我正在做的:

Staff staff = staffService.getEmailInstance(body.getEmailId());
request.getSession(true).setAttribute("staff", staff);

注销就是这样:

request.getSession().invalidate();

在不同的控制器中,我调用此实用程序方法来检查员工是否已登录:util.isStaffLoggedIn(request, response, StaffRole.EDITOR); 如果员工已登录,则 API 继续,否则用户将被重定向到登录页面。< /p>

@Service
public class Util {

    public boolean isStaffLoggedIn(HttpServletRequest request, HttpServletResponse response, StaffRole staffRole)
            throws PaperTrueInvalidCredentialsException, PaperTrueJavaException {
        Staff staff = (Staff) request.getSession().getAttribute("staff");
        if (!isObjectNull(staff) && staff.getStaffRole().equals(staffRole)) {
            return true;
        }
        invalidateSessionAndRedirect(request, response);
        return false;
    }


    public void invalidateSessionAndRedirect(HttpServletRequest request, HttpServletResponse response)
            throws PaperTrueJavaException, PaperTrueInvalidCredentialsException {
        request.getSession().invalidate();
        try {
            response.sendRedirect(ProjectConfigurations.configMap.get("staff_logout_path"));
        } catch (IOException e) {
            throw new PaperTrueJavaException(e.getMessage());
        }
        throw new PaperTrueInvalidCredentialsException("Staff not loggedIn");
    }
}

现在,当应用运行时,get-jobs API 会在成功登录后立即调用。大多数情况下,request.getSession().getAttribute("staff") 方法工作正常并返回“staff”对象,但偶尔会返回 null。这并不经常发生,但确实发生了。我打印了会话 ID 以查看注销后它们是否不同,并且确实如此。每次注销后,我都有一个新的会话 ID。我什至检查了我从数据库中检索到的员工对象是否为空,但不是。

人员对象已成功保存在会话中,但我无法在其他 API 中检索它。这是我的会话配置的样子:

@EnableRedisHttpSession(maxInactiveIntervalInSeconds = 10800)
public class SessionConfig {

    HashMap<String, String> configMap = ProjectConfigurations.configMap;

    @Bean
    public LettuceConnectionFactory connectionFactory() {
        int redisPort = Integer.parseInt(configMap.get("redis_port"));
        RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration(
                configMap.get("redis_host"), redisPort);
        redisStandaloneConfiguration.setPassword(configMap.get("redis_password"));
        return new LettuceConnectionFactory(redisStandaloneConfiguration);
    }

    @Bean
    public CookieSerializer cookieSerializer() {
        DefaultCookieSerializer serializer = new DefaultCookieSerializer();
        serializer.setCookieName("PTSESSIONID");
        serializer.setSameSite("none");
        serializer.setUseSecureCookie(!configMap.get("staff_logout_path").contains("localhost"));
        return serializer;
    }
}

如果我遗漏了什么,请告诉我。提前致谢。

更新 1

我不再使会话无效,而是将 request.getSession(true).setAttribute("staff", staff); 替换为 request.getSession().setAttribute("staff", staff);

我正在 StaffController 中设置“staff”并在 EditorController 中获取它。这是我的设置方式:

@RestController
@RequestMapping(path = { "/staff" }, produces = "application/json")
public class StaffApiController {

    private final HttpServletRequest request;
    private final HttpSession httpSession;

    @Autowired
    private StaffService staffService;

    @Autowired
    StaffApiController(HttpServletRequest request, HttpServletResponse response, HttpSession session) {
        this.request = request;
        this.httpSession = session;
    }

    @PostMapping("/login")
    public ResponseEntity<StaffLoginResponse> login(@Valid @RequestBody StaffLoginBody body) {
        StaffLoginResponse staffLoginResponse = new StaffLoginResponse();
        try {
            if (!staffService.isValidLogin(body.getEmailId(), body.getPassword())) {
                throw new PaperTrueInvalidCredentialsException("Invalid Credentials");
            }

            Staff staff = staffService.getEmailInstance(body.getEmailId());
            httpSession.setAttribute("staff", staff);

            staffLoginResponse.setEmail(staff.getEmail()).setRole(staff.getStaffRole().getValue())
                    .setStaffID(staff.getId()).setStatus(new Status("Staff Login Successful"));
        } catch (PaperTrueException e) {
            httpSession.removeAttribute("staff");
            staffLoginResponse.setStatus(new Status(e.getCode(), e.getMessage()));
        }
        return ResponseEntity.ok(staffLoginResponse);
    }

    @PostMapping("/logout")
    public ResponseEntity<Status> logout() {
        httpSession.removeAttribute("staff");
        return ResponseEntity.ok(new Status("Staff Logged Out Successfully"));
    }

}

1 个答案:

答案 0 :(得分:1)

如果您使用的是 Spring Security,您可以创建一个自定义的“/login”端点,通过设置 SecurityContext 来验证用户的身份。
您可以使用 Spring Security 提供的默认注销行为。
如果不需要在正文中提供凭据,则可以使用 Spring Security 提供的默认登录行为并完全省略此 Controller。

这是一个起点。
它不提供全面的安全性,例如它可能是易受攻击的会话固定攻击。

@RestController
public class LoginController {

    private AuthenticationManager authenticationManager;

    public LoginController(AuthenticationManager authenticationManager) {
        this.authenticationManager = authenticationManager;
    }

    @PostMapping("/login")
    public void login(@RequestBody StaffLoginBody body, HttpServletRequest request) {
        UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(body.getUsername(), body.getPassword());
        Authentication auth = authenticationManager.authenticate(token);
        SecurityContextHolder.getContext().setAuthentication(auth);
        HttpSession session = request.getSession();
        session.setAttribute("staff", "staff_value");
    }

    @GetMapping("/jobs")
    public String getStaffJobs(HttpServletRequest request) {
        return request.getSession().getAttribute("staff").toString();
    }
}
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    // expose AuthenticationManager bean to be used in Controller
    @Override
    @Bean
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests(authorize -> authorize
                .antMatchers("/login").permitAll()
                .anyRequest().authenticated()
            )
            // use built in logout
            .logout(logout -> logout
                .deleteCookies("PTSESSIONID")
            );
    }
}

您需要添加 Spring Security 依赖项才能使用此代码 org.springframework.boot:spring-boot-starter-security

相关问题