2536-springsecurity系列--关于session管理1
阅读原文时间:2023年07月11日阅读:1

版本信息

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.5.14.RELEASE</version>
    <relativePath/> <!-- lookup parent from repository -->
</parent>

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
    <version>1.5.14.RELEASE</version>
    <!--实际里面spring-security-web的版本是4.2.7-->
</dependency>

在ss中基本的session管理

  • session无效处理

  • session过期处理

  • 并发登录处理

  • 限制同一用户重复登录和顶号

    // 配置session相关
    // CustomSecurityProperties是自定义的常量参数类
    private void configSession(HttpSecurity http) throws Exception {
        http.sessionManagement()
                .invalidSessionStrategy(invalidSessionStrategy) //session无效处理策略
                .invalidSessionUrl(CustomSecurityProperties.invalidSessionUrl)
                .maximumSessions(1)  //同一用户最大session数
                .maxSessionsPreventsLogin(false) //达到最大数禁止登录(预防并发登录)
                .expiredSessionStrategy(sessionInformationExpiredStrategy) //session过期处理策略
                .expiredUrl(CustomSecurityProperties.expiredSessionUrl);
    }

并发登录处理

例如用户在两台电脑上登录,并在两台电脑上办公,可设置maximumSessions值为2,这样springsecurity在管理session时会对该用户保持两个有效的session。

限制同一用户重复登录和顶号

例如要求用户最多只能在一台电脑上登录,并且另一台电脑登录会顶掉之前的登录信息。

maximumSessions设置为1

maxSessionsPreventsLogin设置为false

例如要求用户最多只能在一台电脑上登录,并且另一台电脑登录会提示不可重复登录。

maximumSessions设置为1

maxSessionsPreventsLogin设置为true

session无效处理和session过期处理

简单的处理,只是进行url跳转,配置invalidSessionUrl和expiredUrl两个参数即可。

如果需要记录session无效或过期时的用户信息、日志等,需要自定义实现类InvalidSessionStrategy和SessionInformationExpiredStrategy

自定义处理

自定义三个类
AbstractSessionStrategy
CustomExpiredSessionStrategy
CustomInvalidSessionStrategy

在config类中进行配置

    /**
     * 配置sec的session失效策略
     * 配置给sessionManagement
     */
    @Bean
    @ConditionalOnMissingBean(InvalidSessionStrategy.class)
    public InvalidSessionStrategy invalidSessionStrategy() {
        return new CustomInvalidSessionStrategy(CustomSecurityProperties.invalidSessionUrl);
    }

    /**
     * 配置sec的session过期策略
     * 配置给sessionManagement
     */
    @Bean
    @ConditionalOnMissingBean(SessionInformationExpiredStrategy.class)
    public SessionInformationExpiredStrategy sessionInformationExpiredStrategy() {
        return new CustomExpiredSessionStrategy(CustomSecurityProperties.invalidSessionUrl);
    }

三个实现类的代码:

AbstractSessionStrategy

import com.company.testss12.support.RetVO;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.security.web.DefaultRedirectStrategy;
import org.springframework.security.web.RedirectStrategy;
import org.springframework.security.web.util.UrlUtils;
import org.springframework.util.Assert;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * @author starmoon1994
 */
public class AbstractSessionStrategy {

    private final Logger logger = LoggerFactory.getLogger(getClass());
    /**
     * 跳转的url
     */
    private String destinationUrl;
    /**
     * 重定向策略
     */
    private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
    /**
     * 跳转前是否创建新的session
     */
    private boolean createNewSession = true;

    private ObjectMapper objectMapper = new ObjectMapper();

    /**
     */
    public AbstractSessionStrategy(String invalidSessionUrl) {
        Assert.isTrue(UrlUtils.isValidRedirectUrl(invalidSessionUrl), "url must start with '/' or with 'http(s)'");
        this.destinationUrl = invalidSessionUrl;
    }

    protected void onSessionInvalid(HttpServletRequest request, HttpServletResponse response) throws IOException {

        logger.info("onSessionInvalid IP:{}   URI:{}", request.getRemoteHost(), request.getRequestURI());

        if (createNewSession) {
            request.getSession();
        }

        String sourceUrl = request.getRequestURI();
        String targetUrl;

        if (StringUtils.endsWithIgnoreCase(sourceUrl, ".html")) {
            targetUrl = destinationUrl;//+".html";
            logger.info("session失效,跳转到" + targetUrl);
            redirectStrategy.sendRedirect(request, response, targetUrl);
        } else {
            String message = "session已失效,请重新登录";
            if (isConcurrency()) {
                message = message + ",有可能是并发登录导致的";
            }
            response.setStatus(HttpStatus.UNAUTHORIZED.value());
            response.setContentType("application/json;charset=UTF-8");

            RetVO retVO = new RetVO();
            retVO.setMsg(message);
            response.getWriter().write(objectMapper.writeValueAsString(retVO));
        }

    }

    /**
     * session失效是否是并发导致的
     */
    protected boolean isConcurrency() {
        return false;
    }

    /**
     * Determines whether a new session should be created before redirecting (to
     * avoid possible looping issues where the same session ID is sent with the
     * redirected request). Alternatively, ensure that the configured URL does
     * not pass through the {@code SessionManagementFilter}.
     *
     * @param createNewSession defaults to {@code true}.
     */
    public void setCreateNewSession(boolean createNewSession) {
        this.createNewSession = createNewSession;
    }

}

CustomExpiredSessionStrategy

import org.springframework.security.web.session.SessionInformationExpiredEvent;
import org.springframework.security.web.session.SessionInformationExpiredStrategy;

import java.io.IOException;

/**
 * session失效策略
 */
public class CustomExpiredSessionStrategy extends AbstractSessionStrategy implements SessionInformationExpiredStrategy {

    public CustomExpiredSessionStrategy(String invalidSessionUrl) {
        super(invalidSessionUrl);
    }

    @Override
    public void onExpiredSessionDetected(SessionInformationExpiredEvent event) throws IOException {
        onSessionInvalid(event.getRequest(), event.getResponse());
    }

    @Override
    protected boolean isConcurrency() {
        return true;
    }

}

CustomInvalidSessionStrategy

import org.springframework.security.web.session.InvalidSessionStrategy;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * @author starmoon1994
 */
public class CustomInvalidSessionStrategy extends AbstractSessionStrategy implements InvalidSessionStrategy {

    public CustomInvalidSessionStrategy(String invalidSessionUrl) {
        super(invalidSessionUrl);
    }

    @Override
    public void onInvalidSessionDetected(HttpServletRequest request, HttpServletResponse response)
            throws IOException {
        onSessionInvalid(request, response);
    }

}

完整项目工程参考

https://github.com/starmoon1994/springsecurity-collection