天天看點

SpringSecurity的單機session管理、session逾時處理、session失效保證使用者隻能登入一個浏覽器,換一個會擠掉前一個登入session逾時處理 session并發控制session叢集管理

目錄

session逾時處理

session并發控制

如果要進行其他的一些特殊處理,比如判斷是誰擠掉了上一個session,在@configuration中

如果要保證第一個浏覽器登入,不讓其他浏覽器登入

session叢集管理

session逾時處理

在配置檔案加上時間

//機關是秒,預設是30分鐘
server.session.timeout = 10
           

配置了上面的沒有生效,我們檢視源碼的,找到TomcatEmbeddedServletContainerFactory

private void configureSession(Context context) {
        long sessionTimeout = this.getSessionTimeoutInMinutes();
        context.setSessionTimeout((int)sessionTimeout);
        if (this.isPersistSession()) {
            Manager manager = context.getManager();
            if (manager == null) {
                manager = new StandardManager();
                context.setManager((Manager)manager);
            }

            this.configurePersistSession((Manager)manager);
        } else {
            context.addLifecycleListener(new 
TomcatEmbeddedServletContainerFactory.DisablePersistSessionListener());
        }

    }
           
private long getSessionTimeoutInMinutes() {
        long sessionTimeout = (long)this.getSessionTimeout();
        if (sessionTimeout > 0L) {
        //秒數轉換成分鐘,傳回的是最小分鐘數字,6s會變成1分鐘
            sessionTimeout = Math.max(TimeUnit.SECONDS.toMinutes(sessionTimeout), 1L);
        }

        return sessionTimeout;
    }
           

在@configuration,SpringSecurity配置中加上

.and()
.sessionManagement()
//session失效的時候,跳轉的位址
.invalidSessionUrl("/session/invalid")
.and()
           

session失效之後跳轉

@GetMapping("/session/invalid")
	@ResponseStatus(code = HttpStatus.UNAUTHORIZED)
	public SimpleResponse valid(){
		return new SimpleResponse("session失效了");
	}
           

session并發控制

常見場景:一個使用者隻能有一個session,使用者在另一個地方登陸的時候,把其他地方的session失效掉

設定session失效時間和最大session數

//機關是秒,預設是30分鐘
server.session.timeout = 600
           
//session失效的時候,跳轉的位址
.and()
.sessionManagement()
.invalidSessionUrl("/session/invalid")
//最大session線上數,可以通過配置檔案加載
.maximumSessions(1)
.and()
           

如果要進行其他的一些特殊處理,比如判斷是誰擠掉了上一個session,在@configuration中

//session失效的時候,跳轉的位址
.sessionManagement()
.invalidSessionUrl("/session/invalid")
.maximumSessions(1)
//imoocExpiredSessionStrategy 中包含session過期之後,跳轉到的頁面
.expiredSessionStrategy(imoocExpiredSessionStrategy )
           

建立SessionInformationExpiredStrategy類

public class ImoocExpiredSessionStrategy extends AbstractSessionStrategy implements SessionInformationExpiredStrategy {

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

	/* (non-Javadoc)
	 * @see org.springframework.security.web.session.SessionInformationExpiredStrategy#onExpiredSessionDetected(org.springframework.security.web.session.SessionInformationExpiredEvent)
	 */
	@Override
	public void onExpiredSessionDetected(SessionInformationExpiredEvent event) throws IOException, ServletException {
        //調用抽象方法,session失效
		onSessionInvalid(event.getRequest(), event.getResponse());
	}
	
	/* (non-Javadoc)
	 * @see com.imooc.security.browser.session.AbstractSessionStrategy#isConcurrency()
	 */
	@Override
	protected boolean isConcurrency() {
		return true;
	}

}
           
AbstractSessionStrategy
           
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();

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

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.springframework.security.web.session.InvalidSessionStrategy#
	 * onInvalidSessionDetected(javax.servlet.http.HttpServletRequest,
	 * javax.servlet.http.HttpServletResponse)
	 */
	protected void onSessionInvalid(HttpServletRequest request, HttpServletResponse response) throws IOException {

		logger.info("session失效");
		
		if (createNewSession) {
			request.getSession();
		}

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

		if (StringUtils.endsWithIgnoreCase(sourceUrl, ".html")) {
			targetUrl = destinationUrl;
			logger.info("跳轉到:"+targetUrl);
			redirectStrategy.sendRedirect(request, response, targetUrl);
		} else {
			Object result = buildResponseContent(request);
			response.setStatus(HttpStatus.UNAUTHORIZED.value());
			response.setContentType("application/json;charset=UTF-8");
			response.getWriter().write(objectMapper.writeValueAsString(result));
		}

	}

	/**
	 * @param request
	 * @return
	 */
	protected Object buildResponseContent(HttpServletRequest request) {
		String message = "session已失效";
		if (isConcurrency()) {
			message = message + ",有可能是并發登入導緻的";
		}
		return new SimpleResponse(message);
	}

	/**
	 * session失效是否是并發導緻的
	 * 
	 * @return
	 */
	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;
	}

}
           
AbstractSessionStrategy
           

這個時候,啟動兩個浏覽器,隻能有一個浏覽器登入成功

如果要保證第一個浏覽器登入,不讓其他浏覽器登入

在@configuration加上配置

.and()
.sessionManagement()
//session失效的時候,跳轉的位址
.invalidSessionUrl("/session/invalid")
.maximumSessions(1)
.invalidSessionStrategy(invalidSessionStrategy)
.maximumSessions(1)
//當session達到maximumSessions,阻止後來的session登入
.maxSessionsPreventsLogin(true)
.expiredSessionStrategy(sessionInformationExpiredStrategy)
.and()
           

session叢集管理

繼續閱讀