Spring Security : 概念模型 SecurityContext 安全上下文

概述

介绍

Spring Security使用接口SecurityContext抽象建模"安全上下文"这一概念。这里安全上下文SecurityContext指的是当前执行线程使用的最少量的安全信息(其实就是用于代表访问者账号的有关信息)。当一个线程在服务用户期间,该安全上下文对象会保存在SecurityContextHolder中。

SecurityContextHolder类提供的功能是保持SecurityContext,不过它的用法不是让使用者创建多个SecurityContextHolder对象,而是提供一组公开静态工具方法。基于这组方法,SecurityContextHolder主要提供了两种管理SecurityContext的模式 :

  1. 全局模式

    对整个应用公开保持一个SecurityContext,这种模式下,应用中的多个线程同一时间通过SecurityContextHolder访问到的都会是同一个SecurityContext对象;

  2. 线程本地模式

    对应用中的某个线程保持一个SecurityContext,这种模式下,应用中的每个线程同一时间通过SecurityContextHolder访问到的都是关于自己线程的SecurityContext;

SecurityContext中保存的"最少量的安全信息"其实是通过Authentication对象所携带的信息。它用于代表当前访问者。如果当前访问者尚未认证但正在认证,Authentication内包含的是认证请求信息,比如用户名密码等等。如果当前访问者已经被认证,则Authentication会包含更多当前访问者的信息,比如权限,用户详情等等。另外即使访问者一直在访问一些不需要登录认证的公开资源,也有可能存在Authentication对象,此时Authentication会是一种特殊的类型,专门用于表示这是一个匿名用户。

Spring Security为接口SecurityContext提供了一个缺省实现SecurityContextImpl并在框架内各处缺省。

使用

        // HttpServlet3RequestFactory 代码片段
		@Override
		public void login(String username, String password) throws ServletException {
			// ...
			Authentication authentication;
			try {
				authentication = authManager.authenticate(
						new UsernamePasswordAuthenticationToken(username, password));
			}
			catch (AuthenticationException loginFailed) {
             // 认证失败,清除 SecurityContextHolder 中的安全上下文
				SecurityContextHolder.clearContext();
				throw new ServletException(loginFailed.getMessage(), loginFailed);
			}
          // 认证成功,设置认证对象到  SecurityContextHolder 中的安全上下文
			SecurityContextHolder.getContext().setAuthentication(authentication);
		}

		@Override
		public void logout() throws ServletException {
			LogoutHandler handler = HttpServlet3RequestFactory.this.logoutHandler;
			// ...
			Authentication authentication = SecurityContextHolder.getContext()
					.getAuthentication();
          
          // 退出登录处理器也需要从 SecurityContextHolder 中获取安全上下文中的认证对象进行处理
			handler.logout(this, this.response, authentication);
		}

源代码

源代码版本 Spring Security Web 5.1.4.RELEASE

SecurityContext 接口


package org.springframework.security.core.context;

import org.springframework.security.core.Authentication;

import java.io.Serializable;

/**
 * Interface defining the minimum security information associated with the current thread
 * of execution.
 *
 * 
 * The security context is stored in a SecurityContextHolder.
 * 
 *
 * @author Ben Alex
 */
public interface SecurityContext extends Serializable {
	// ~ Methods
	// ============================================================

	/**
	 * Obtains the currently authenticated principal, or an authentication request token.
	 *
	 * @return the Authentication or null if no authentication
	 * information is available
	 */
	Authentication getAuthentication();

	/**
	 * Changes the currently authenticated principal, or removes the authentication
	 * information.
	 *
	 * @param authentication the new Authentication token, or
	 * null if no further authentication information should be stored
	 */
	void setAuthentication(Authentication authentication);
}

缺省实现 SecurityContextImpl

Spring Security为接口SecurityContext提供的缺省实现SecurityContextImpl,该实现逻辑其实很简单,主要就是保持一个Authentication`对象。

package org.springframework.security.core.context;

import org.springframework.security.core.Authentication;
import org.springframework.security.core.SpringSecurityCoreVersion;

/**
 * Base implementation of SecurityContext.
 * 
 * Used by default by SecurityContextHolder strategies.
 *
 * @author Ben Alex
 */
public class SecurityContextImpl implements SecurityContext {

	private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID;

	// ~ Instance fields
	// ======================================================

	private Authentication authentication;

	public SecurityContextImpl() {}

	public SecurityContextImpl(Authentication authentication) {
		this.authentication = authentication;
	}

	// ~ Methods
	// ======================================================

	@Override
	public boolean equals(Object obj) {
		if (obj instanceof SecurityContextImpl) {
			SecurityContextImpl test = (SecurityContextImpl) obj;

			if ((this.getAuthentication() == null) && (test.getAuthentication() == null)) {
				return true;
			}

			if ((this.getAuthentication() != null) && (test.getAuthentication() != null)
					&& this.getAuthentication().equals(test.getAuthentication())) {
				return true;
			}
		}

		return false;
	}

	@Override
	public Authentication getAuthentication() {
		return authentication;
	}

	@Override
	public int hashCode() {
		if (this.authentication == null) {
			return -1;
		}
		else {
			return this.authentication.hashCode();
		}
	}

	@Override
	public void setAuthentication(Authentication authentication) {
		this.authentication = authentication;
	}

	@Override
	public String toString() {
		StringBuilder sb = new StringBuilder();
		sb.append(super.toString());

		if (this.authentication == null) {
			sb.append(": Null authentication");
		}
		else {
			sb.append(": Authentication: ").append(this.authentication);
		}

		return sb.toString();
	}
}

参考文章

你可能感兴趣的:(Spring,Security,分析)