[SpringCloud] Spring Security Core Components

1. Core components

1.1 SecurityContextHolder类

1.1.1 Concept

SecurityContextHolder is well-known by its name. It is a holder that holds information about the security context.

insert image description here

SecurityContextHolder records the following information: who is the user currently operating, whether the user has been authenticated, what roles or permissions he has, and so on.

In a typical web application, users log in once and are then identified by their session ID. The server caches session principal information for the duration. In Spring Security, the responsibility for storing the SecurityContext between requests falls on the SecurityContextPersistenceFilter, which by default stores the context as an HttpSession attribute between HTTP requests. It restores the context SecurityContextHolder for each request, and most importantly, clears the SecurityContextHolder when the request completes. SecurityContextHolder is a class, and its functional methods are all static (static).

1.1.2 Storage Policy

A total of 3 strategies are included:
1 Stored in the thread
2 Stored in the thread, but the child thread can get the SecurityContext in the parent thread.
3 is the same in all threads.

SecurityContextHolder uses ThreadLocal strategy to store authentication information by default. Seeing ThreadLocal also means that this is a thread-bound strategy. In the web environment, Spring Security automatically binds the authentication information to the current thread when the user logs in, and automatically clears the authentication information of the current thread when the user logs out.

1.1.3 Source code

SecurityContextHolder adopts the strategy mode and creates different SecurityContextHolderStrategy objects according to the strategyName field.

public class SecurityContextHolder {
    
    
	// 三种存储策略
	public static final String MODE_THREADLOCAL = "MODE_THREADLOCAL";
	public static final String MODE_INHERITABLETHREADLOCAL = "MODE_INHERITABLETHREADLOCAL";
	public static final String MODE_GLOBAL = "MODE_GLOBAL";
	
	public static final String SYSTEM_PROPERTY = "spring.security.strategy";
	
	// System.getProperty() 从JVM中获取配置的属性SYSTEM_PROPERTY
	// 获取不到 strategyName = null
	private static String strategyName = System.getProperty(SYSTEM_PROPERTY);
	private static SecurityContextHolderStrategy strategy;
	private static int initializeCount = 0;
	
	// 随着类的加载而加载
	static {
    
    
		initialize();
	}

	...
	
	// 初始化
	private static void initialize() {
    
    
		if (!StringUtils.hasText(strategyName)) {
    
    
			// 设置默认策略
			strategyName = MODE_THREADLOCAL;
		}
		
		// 根据strategyName字段创建对应的SecurityContextHolderStrategy对象
		if (strategyName.equals(MODE_THREADLOCAL)) {
    
    
			strategy = new ThreadLocalSecurityContextHolderStrategy();
		}
		else if (strategyName.equals(MODE_INHERITABLETHREADLOCAL)) {
    
    
			strategy = new InheritableThreadLocalSecurityContextHolderStrategy();
		}
		else if (strategyName.equals(MODE_GLOBAL)) {
    
    
			strategy = new GlobalSecurityContextHolderStrategy();
		}
		else {
    
    
			// 自定义策略
			...
		}

		initializeCount++;
	}

	// 
	public static void setContext(SecurityContext context) {
    
    
		strategy.setContext(context);
	}

	// 可以设置新的存储策略
	public static void setStrategyName(String strategyName) {
    
    
		SecurityContextHolder.strategyName = strategyName;
		// 修改strategyName后需要重新执行initialize创建新的SecurityContextHolderStrategy对象
		initialize();
	}
	...
}

1.2 SecurityContext interface

Security context, after the user passes the verification of Spring Security, the verification information is stored in the SecurityContext. The SecurityContext interface only defines two methods. In fact, its main function is to set and obtain the Authentication object.

public interface SecurityContext extends Serializable {
    
    
	Authentication getAuthentication();
	void setAuthentication(Authentication authentication);
}

1.3 Authentication interface

Authentication literally means "authentication". In Spring Security, Authentication is used to indicate who the current user is. Generally speaking, you can understand that authentication is a set of username and password information.

Authentication includes :

1 principal: used to identify users When authenticating users through username and password, the principal is usually an implementation class object of UserDetails.
2 credentials: usually a password. In many scenarios, if the user has been authenticated, this item will be cleared to prevent password leakage.
3 authorities: The authority or role that the user has.

public interface Authentication extends Principal, Serializable {
    
    
	//权限信息列表,默认是GrantedAuthority接口的一些实现类,通常是代表权限信息的一系列字符串。
	Collection<? extends GrantedAuthority> getAuthorities();
	
	//密码信息,用户输入的密码字符串,在认证过后通常会被移除,用于保障安全
	Object getCredentials();
	
	//细节信息,web应用中的实现接口通常为 WebAuthenticationDetails,它记录了访问者的ip地址和sessionId的值。
	Object getDetails();
	
	//最重要的身份信息,大部分情况下返回的是UserDetails接口的实现类,也是框架中的常用接口之一。
	Object getPrincipal();
	
	boolean isAuthenticated();
	
	void setAuthenticated(boolean var1) throws IllegalArgumentException;
}

Case: Get the username of the authenticated user.

//getAuthentication()返回了认证信息
//getPrincipal()返回了身份信息,UserDetails便是Spring对身份信息封装的一个接口。
Object principal =SecurityContextHolder.getContext().getAuthentication().getPrincipal();
if (principal instanceof UserDetails) {
    
    
	String username = ((UserDetails)principal).getUsername();
} else {
    
    
	String username = principal.toString();
}

1.4 GrantedAuthority interface

Use collections to store permissions in the Authentication interface

Collection<? extends GrantedAuthority> getAuthorities();

You can see that the elements stored in the permission collection are GrantedAuthoritythe implementation classes, and you can also use String.

This interface represents the permission (or role) information of the current user. This information is used by the authorized object AccessDecisionManager to decide whether the end user can access a resource.

1.5 UserDetails interface

This interface standardizes the fields owned by user details, such as user name, password, whether the account is expired, whether it is locked, etc. In Spring Security, to obtain the information of the currently logged-in user, it is generally necessary to extend this interface to connect to users of your own system

public interface UserDetails extends Serializable {
    
    
	Collection<? extends GrantedAuthority> getAuthorities();
	String getPassword();
	String getUsername();
	// 用户账户是否过去,过期的用户不能被认证
	boolean isAccountNonExpired();
	 // 用户是否被lock,lock的用户不能被认证
	boolean isAccountNonLocked();
	 // 用户的credentials (password)是否过期,国企的不能认证成功
	boolean isCredentialsNonExpired();
	 // 用户是enabled或者disabled,diabled的用户不能被认证
	boolean isEnabled();
}

1.6 UserDetailsService interface

public interface UserDetailsService {
    
    
	UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;
}

This interface is very important. Generally, we display and obtain our user information by extending this interface. The user name and password passed by the user when logging in are also verified by the user name and password found here.

But the real verification is not here, but by AuthenticationManager and AuthenticationProvider. It should be emphasized that if the user does not exist, NULL should not be returned, but an exception UsernameNotFoundException should be thrown.

1.7 AuthenticationManager interface

public interface AuthenticationManager {
    
    
	Authentication authenticate(Authentication authentication) throws AuthenticationException;
}

AuthenticationManager is the core interface related to authentication, and it is also the starting point for initiating authentication, because in actual needs, we may allow users to log in with username + password, and at the same time allow users to log in with email address + password, mobile phone number + password, or even allow User logs in with fingerprint.

Therefore, AuthenticationManager generally does not directly authenticate. ProviderManager, a commonly used implementation class of AuthenticationManager interface, maintains a List<AuthenticationProvider>list inside to store multiple authentication methods. In fact, this is the application of the delegator mode (Delegate).
insert image description here

There is always only one core authentication entry: AuthenticationManager. Different authentication methods include: username + password, email + password, mobile phone number + password login, which correspond to three AuthenticationProviders respectively.

1.8 DaoAuthenticationProvider

AuthenticationProvider interface

public interface AuthenticationProvider {
    
    
	Authentication authenticate(Authentication authentication) throws AuthenticationException;
	boolean supports(Class<?> authentication);
}

One of the most commonly used implementations of the AuthenticationProvider interface is DaoAuthenticationProvider.

As the name suggests, Dao is the abbreviation of Data Access Layer, which also implies the implementation idea of ​​this identity authenticator. Main function: It obtains the user name and password submitted by the user, compares their correctness, and if correct, returns the user information in a database (assuming that the user information is stored in the database).

2. Summary

2.1 UserDetails和UserDetailsService

The UserDetails interface represents the most detailed user information. This interface contains some necessary user information fields, and we generally need to make necessary extensions to it.

It is very similar to the Authentication interface, for example, they both have username and authorities.

Authentication's getCredentials() and UserDetails' getPassword() need to be treated differently. The former is the password credential submitted by the user, while the latter is the user's correct password. The authenticator is actually a comparison between the two.

The getAuthorities() in Authentication is actually formed by passing the getAuthorities() of UserDetails. Remember the getUserDetails() method in the Authentication interface? The UserDetails user details are filled after passing the AuthenticationProvider.

The responsibilities of UserDetailsService and AuthenticationProvider are often confused by people. UserDetailsService is only responsible for loading user information from specific places, which can be databases, redis caches, interfaces, etc.

2.2 How Spring Security completes identity authentication

(1) The username and password are obtained by the filter and encapsulated into Authentication, usually the UsernamePasswordAuthenticationToken implementation class.
(2) The AuthenticationManager identity manager is responsible for verifying the Authentication
(3) After the authentication is successful, the AuthenticationManager identity manager returns a message filled with information (including the above-mentioned permission information, identity information, and detailed information, but the password is usually remove) the Authentication instance.
(4) The SecurityContextHolder security context container sets the Authentication filled with information in step 3 into it through the SecurityContextHolder.getContext().setAuthentication() method.

reference:

1 spring security series one: core components
2 Spring Security Authentication Architecture

Guess you like

Origin blog.csdn.net/See_Star/article/details/125083000