Spring Security 之 Session Management

     Spring  Security为我们提供了SessionAuthenticationStrategy接口来定制针对Session的一些特殊管理,如防Session的固定攻击, 防Session的单用户多次登陆等, 这些特殊的管理功能Spring Security都为我们提供了相应的类,如下示:


      1. SessionFixationProtectionStrategy, 这个实现SessionAuthenticationStrategy的类是用于防止Session的固定攻击的

      这里先从Session的固定攻击说起, 话说什么是Session的固定攻击呢, 当我们尝试登录时, Spring Security会为我们创建一个Session, 并将SessionId放置在Cookie或URL中, 如果没有使用Spring Security的防Session固定攻击的功能的话, 当用户登录成功后, 这个SessionId是不会改变的, 如果在登录前这个SessionId就因为某种原因而被窃取了,那就会让别有用心者在不知道用户账户的情况下, 通过使用SessionId来达到查看需用户登录的资源。 那么Spring Security又是如何来解决这个问题的呢, 办法很简单, 在用户登录成功后重新创建一个Session, 并将旧有Session的信息转移到新建的Session中, 当然这是可选的, 至于你想不想转移这些信息或者转移哪些信息这些都是可以选择的, 可由用户自主选择。

      源码解释

    //是否需要转移Session中的值
    private boolean migrateSessionAttributes = true;

    //需要转移的Session中的值的列表
    private List<String> retainedAttributes = null;

    //是否创建新的Session
    private boolean alwaysCreateSession;

    //该方法是实现Session管理的主方法, 也就是SessionAuthenticationStrategy接口中的方法
    public void onAuthentication(Authentication authentication, HttpServletRequest request, HttpServletResponse response) {
        boolean hadSessionAlready = request.getSession(false) != null;
        //如果没有Session存在则返回不做处理
        if (!hadSessionAlready && !alwaysCreateSession) {
            

            return;
        }

        // 创建一个Session
        HttpSession session = request.getSession();

        if (hadSessionAlready && request.isRequestedSessionIdValid()) {
            // We need to migrate to a new session
            String originalSessionId = session.getId();

            if (logger.isDebugEnabled()) {
                logger.debug("Invalidating session with Id '" + originalSessionId +"' " + (migrateSessionAttributes ?
                        "and" : "without") +  " migrating attributes.");
            }

            Map<String, Object> attributesToMigrate = extractAttributes(session);

            session.invalidate();
            session = request.getSession(true); // we now have a new session

            if (logger.isDebugEnabled()) {
                logger.debug("Started new session: " + session.getId());
            }

            if (originalSessionId.equals(session.getId())) {
                logger.warn("Your servlet container did not change the session ID when a new session was created. You will" +
                        " not be adequately protected against session-fixation attacks");
            }
            //转移Session中的属性值
            transferAttributes(attributesToMigrate, session);
	    //Session转移后需要做的额外工作, 当前类中的方法为空方法,可由用户自主实现
            onSessionChange(originalSessionId, session, authentication);
        }
    }
 


      2. ConcurrentSessionControlStrategy这个类是用于防止Session的单用户多次登陆的, 值得一提的是ConcurrentSessionControlStrategy是SessionFixationProtectionStrategy的子类,所以SessionFixationProtectionStrategy类也具有防Session的固定攻击的功能

      在没有这个辅助类的情况下, 有这样一种情况我们无法避免, 那就是同一个用户在不同机器的不同浏览器上可以进行多次登录, 如果我们希望杜绝这种情况的发生, 就需要使用到这个类, 用来控制同一个用户同一时刻最多的登录次数, 如果设置maximumSessions为1, 表时只希望用户在同一时刻只能登录一次。那么Spring Security又是如何控制用户登录次数的呢, 这就需要讲到sessionRegistry这个接口了, 它有个默认实现SessionRegistryImpl, 当用户登录成功后,会调用registerNewSession方法,将当前用户登录的一些基本信息如SessionId, 用户名等放置在内存中, 那么当同一用户再次登录时, 会调用sessionRegistry的getAllSessions方法, 获取登录用户的登录次数, 再与设置的最大次数比较就可以知道用户是否超出了登录限制。sessionRegistry的getAllPrincipals方法可以得到当前系统中的已登录用户,即在线用户,这非常有用。

      SessionRegistry源码

package org.springframework.security.core.session;

import java.util.List;

/**
 * Maintains a registry of <code>SessionInformation</code> instances.
 *
 * @author Ben Alex
 */
public interface SessionRegistry {
    //获取当前系统的在线用户
    List<Object> getAllPrincipals();

    //根据传入的用户名参数, 获取当前用户的登录信息列表
    List<SessionInformation> getAllSessions(Object principal, boolean includeExpiredSessions);

    //根据SessionId, 获取Session的基本信息,如最后一次访问时间,是否过期等
    SessionInformation getSessionInformation(String sessionId);

    //根据SessionId,更新最后访问时间
    void refreshLastRequest(String sessionId);

    //登录成功后注册一个新的SessionInformation到内存中
    void registerNewSession(String sessionId, Object principal);

    //根据SessionId移除SessionInformation
    void removeSessionInformation(String sessionId);
}
 

      3. Spring Security还为我们提供了一个类叫NullAuthenticatedSessionStrategy,查看源码可以发现只有一个空的方法实现, 从类名也可顾名思义,知道这个类的作用就是什么事也不做

猜你喜欢

转载自dreamzhong.iteye.com/blog/1763098