SpringSecurity(二):security的基本原理

上一章,给大家介绍了如何引入SpringSecurity。但是Security的默认安全校验不是很人性化,

所以我们需要实现自己的个性化校验逻辑。

在实现个性化校验逻辑之前,我们先来看看SpringSecurity的基本原理,以方便我们个性化。


security原理:

使用一系列的过滤器对请求进行拦截,形成一个过滤链。一层一层下来最后到访问rest api为止。

security的登录过滤器为:AbstractAuthenticationProcessingFilter

默认的登录为basic登录,过滤器为:BasicAuthenticationFilter

表单登陆过滤器为:UsernamePasswordAuthenticationFilter


下面我们使用第一节的代码,在BasicAuthenticationFilter类上dubug测试。

主要代码:

	protected void doFilterInternal(HttpServletRequest request,
			HttpServletResponse response, FilterChain chain)
					throws IOException, ServletException {
		//获取请求头中数据
		String header = request.getHeader("Authorization");
		//如果为空或者不是以Basic开头就走下一个过滤链
		if (header == null || !header.startsWith("Basic ")) {
			chain.doFilter(request, response);
			return;
		}

		try {
			//将请求头的数据解析成账户密码
			String[] tokens = extractAndDecodeHeader(header, request);
			assert tokens.length == 2;

			String username = tokens[0];
			//判断是否认证过,通过SecurityContextHolder
			if (authenticationIsRequired(username)) {
				//通过账户密码构建UsernamePasswordAuthenticationToken
				UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(
						username, tokens[1]);
				authRequest.setDetails(
						this.authenticationDetailsSource.buildDetails(request));
				//提交给AuthenticationManager
				Authentication authResult = this.authenticationManager
						.authenticate(authRequest);
				//认证完成以后放入SecurityContextHolder,基于TreadLocal
				SecurityContextHolder.getContext().setAuthentication(authResult);
				//记住我
				this.rememberMeServices.loginSuccess(request, response, authResult);
				//登陆成功的处理。空实现
				onSuccessfulAuthentication(request, response, authResult);
			}

		}
		catch (AuthenticationException failed) {
			SecurityContextHolder.clearContext();

			this.rememberMeServices.loginFail(request, response);

			onUnsuccessfulAuthentication(request, response, failed);

			if (this.ignoreFailure) {
				chain.doFilter(request, response);
			}
			else {
				this.authenticationEntryPoint.commence(request, response, failed);
			}

			return;
		}
		//继续下一个过滤器
		chain.doFilter(request, response);
	}

下面看AuthenticaitonManager,这是一个接口,默认实现为ProviderManager

主要代码:

	public Authentication authenticate(Authentication authentication)
			throws AuthenticationException {
		Class<? extends Authentication> toTest = authentication.getClass();
		
		/**
		 * 遍历容器里的AuthenticationProvider,查看是否支持该authentication
		 * 如果不支持就continue,成功以后不进行后续的尝试
		 * 都不支持则抛出异常
		 * 
		 */
		for (AuthenticationProvider provider : getProviders()) {
			if (!provider.supports(toTest)) {
				continue;
			}
			
		}
	}
上面代码认证通过以后返回一个认证完的Authentication


下面看AuthenticationProvider接口的实现DaoAuthenticationProvider

主要代码:

	protected final UserDetails retrieveUser(String username,
			UsernamePasswordAuthenticationToken authentication)
			throws AuthenticationException {
		UserDetails loadedUser;
		
		/**
		 * 调用UserDetailsService,通过用户名加载用户信息
		 */
		try {
			loadedUser = this.getUserDetailsService().loadUserByUsername(username);
		}
		//其他省略
		return loadedUser;
	}
返回UserDetails实例.UserDetailsService的默认实现是基于内存的。我们在项目中可以把这里改成基于数据库的


下面我们来看看UserDetailsService接口和UserDetails类

public interface UserDetailsService {

	/**
	 * 通过用户名获取用户信息
	 */
	UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;
}

public interface UserDetails extends Serializable {
	
	Collection<? extends GrantedAuthority> getAuthorities();

	String getPassword();

	String getUsername();

	boolean isAccountNonExpired();

	boolean isAccountNonLocked();

	boolean isCredentialsNonExpired();

	boolean isEnabled();
}

最后SecurityContextHolder将认证成功的用户信息保存到session中。



最后,我们来捋一下登陆的基本流程



参考博客:

https://www.cnkirito.moe/2017/09/19/spring-security-1/


  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值