【源码】初探 Spring Security 默认的登录及鉴权方式

暂时忽略的必备知识

  1. spring boot 装配 spring security 的内容
    在这里插入图片描述
    在这里插入图片描述

下文提到的 SecurityAutoConfigurationUserDetailsServiceAutoConfigurationSecurity 的默认实现,至于为什么,涉及spring boot的原理。

  1. spring boot@ConditionalOnXXX@Order 的用法 (涉及到优先级关系,理解后才能知道如何覆盖框架默认实现)
  2. 由于存在自动装配,手动装配不写的情况下也可以用Security。使用手动配置往往是要覆盖默认配置。其中@EnableWebSecurity(debug = true) 装配 Spring Security。其中必要的(debug = true),开日志用于看被装配的Filter。
    在这里插入图片描述
  3. spring frameworkioc 的内容

需要预备知识

  1. spring boot版本 2.2.0

  2. Spring在Servlet应用中,面向切面编程的层次关系

  3. 设计模式:
    模板方法
    责任链

Security 的配置入口

  • SpringBootWebSecurityConfiguration 的【内部类】 DefaultConfigurerAdapter 的实现类为配置入口, 可以看看默认的配置,后期可以模仿编码并覆盖其配置

在这里插入图片描述

  • 默认是空实现,可以自己从0开始配置。但是不妨看看官方给了哪些配置,继承改一下写个demo还是很方便的。
    这里选用WebSecurityConfigurerAdapter
    其中重载了父类的configure方法: configure(HttpSecurity http)
protected void configure(HttpSecurity http) throws Exception {
		logger.debug("Using default configure(HttpSecurity). If subclassed this will potentially override subclass configure(HttpSecurity).");

		http
			.authorizeRequests()
				.anyRequest().authenticated()
				.and()
			.formLogin().and()
			.httpBasic();
	}
  • 默认情况下为form表单提交,点进去看看配置了什么。发现UsernamePasswordAuthenticationFilter
	public FormLoginConfigurer<HttpSecurity> formLogin() throws Exception {
		return getOrApply(new FormLoginConfigurer<>());
	}

	public FormLoginConfigurer() {
		super(new UsernamePasswordAuthenticationFilter(), null);
		usernameParameter("username");
		passwordParameter("password");
	}
	
	public UsernamePasswordAuthenticationFilter() {
		super(new AntPathRequestMatcher("/login", "POST"));
	}
  • UsernamePasswordAuthenticationFilter 配置了POST: /login 的登录url。认证规则中的key的用户名密码usernamepassword

  • UsernamePasswordAuthenticationFilter 使用父类的模板方法,模板方法中又采用了责任链模式。

		public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
			throws IOException, ServletException {
		HttpServletRequest request = (HttpServletRequest) req;
		HttpServletResponse response = (HttpServletResponse) res;

		if (!requiresAuthentication(request, response)) { // 不需要认证的就直接交给下一个Filter
			chain.doFilter(request, response);
			return;
		}

		authResult = attemptAuthentication(request, response); // 需要认证, 回调子类实现进行验证
		// ... 省略
	}
  • attemptAuthentication() 即为默认的认证实现
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) {
		// 最终都是从request的parameter中拿到username 和 password的value
		String username = obtainUsername(request); 
		String password = obtainPassword(request); 
		UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password); // 使用value生成被系统识别的token,属于Web项目Security的流程,如果日后需要用jwt作为token, 需要覆盖
		setDetails(request, authRequest);

		return this.getAuthenticationManager().authenticate(authRequest); // 管理认证的业务逻辑
	}
  • getAuthenticationManager 明显得将获取账号密码、与用账号密码认证的过程解耦了。认证的业务逻辑即可再AuthenticationManager 的实现类中找到。

TODO

AuthenticationManager 的实现类及注入机制比较复杂…搞清楚后再来填坑。这里贴一个参考的流程。
查阅资料知道默认的实现是: ProviderManager
它是一个Filter,最终会被作为Servlet过滤器链中的一个Filter应用到Servlet容器中。安
在这里插入图片描述

Security 如查询可信用户

  • spring boot装配的UserDetailsServiceAutoConfiguration
public class UserDetailsServiceAutoConfiguration {
	@Bean
	@ConditionalOnMissingBean(
			type = "org.springframework.security.oauth2.client.registration.ClientRegistrationRepository")
	@Lazy
	public InMemoryUserDetailsManager inMemoryUserDetailsManager(SecurityProperties properties,
			ObjectProvider<PasswordEncoder> passwordEncoder) {//... 省略}
}
  • 从注解来看是懒加载一个使用内存查询的方式获取用户
    在这里插入图片描述
  • 查看InMemoryUserDetailsManager 的接口UserDetailsManager ,定义了用户的增删改查。是拓展Security的重要接口
    在这里插入图片描述

验证未通过

AuthenticationManager 这个接口方法非常奇特,入参和返回值的类型都是 Authentication 。该接
口的作用是对用户的未授信凭据进行认证,认证通过则返回授信状态的凭据,否则将抛出认证异常
AuthenticationException

  • 所以通常我们都需要ControllerAdvice 进行捕获异常做其他业务的定制化处理

后记

要使用好Spring Security,至少需要懂得一下操作拓展默认实现。

  • 自己定义一个Filte 拓展默认实现,需要用到ioc 的内容。拓展可以是采取责任链模式,放在Security默认的UsernamePasswordAuthenticationFilter 之前
  • 自己定义一个继承AbstractAuthenticationToken 的Token封装类,后期可用jwt实现
  • 自己定义一个实现UserDetailsManager 的类,实现访问自己数据库中的数据用于认证
  • 自己定义一个ControllerAdvice进行捕获AuthenticationException,并进行异常处理

TODO 更详细的操作需要结合具体业务了。

参考

https://felord.cn/categories/spring-security/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值