spring security用户名密码方式源码分析

UsernamePasswordAuthenticationFilter->doFilter

->AbstractAuthenticationProcessingFilter#doFilter

public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
			throws IOException, ServletException {

		...
		Authentication authResult;

		try {
		//step1:获得Authentication对象,这是个抽象方法,具体实现在子类中
			authResult = attemptAuthentication(request, response);
			if (authResult == null) {
				// return immediately as subclass has indicated that it hasn't completed
				// authentication
				return;
			}
			sessionStrategy.onAuthentication(authResult, request, response);
		}
		//step2:如果获得Authentication 对象失败,对失败的Authentication 进行处理
		catch (InternalAuthenticationServiceException failed) {
			logger.error(
					"An internal error occurred while trying to authenticate the user.",
					failed);
			unsuccessfulAuthentication(request, response, failed);

			return;
		}
		catch (AuthenticationException failed) {
			// Authentication failed
			unsuccessfulAuthentication(request, response, failed);

			return;
		}

		// step3: 如果成功,继续处理下一个filter,
		if (continueChainBeforeSuccessfulAuthentication) {
			chain.doFilter(request, response);
		}
//step4:处理成功的处理
		successfulAuthentication(request, response, chain, authResult);
	}

如何生成Authentication 对象?

即上面中第一步的具体方法:
attemptAuthentication(request, response)
->UsernamePasswordAuthenticationFilter#attemptAuthentication

	public Authentication attemptAuthentication(HttpServletRequest request,
			HttpServletResponse response) throws AuthenticationException {
			//只支持post请求
			//获取用户名密码
			//使用用户名密码构建一个Token对象

		UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(
				username, password);

		// Allow subclasses to set the "details" property
		setDetails(request, authRequest);
//核心方法,调用AuthenticationManager().authenticate来完成验证,并返回Authentication对象
		return this.getAuthenticationManager().authenticate(authRequest);
	}

->this.getAuthenticationManager().authenticate(authRequest)
->ProviderManager#authenticate
-> parent.authenticate(authentication)

->ProviderManager#authenticate
->AbstractUserDetailsAuthenticationProvider#authenticate.authenticate(authentication)

user = retrieveUser(username,
(UsernamePasswordAuthenticationToken) authentication);

->DaoAuthenticationProvider#retrieveUser

protected final UserDetails retrieveUser(String username,
			UsernamePasswordAuthenticationToken authentication)
			throws AuthenticationException {
		UserDetails loadedUser;

		try {
			loadedUser = this.getUserDetailsService().loadUserByUsername(username);

->DemoUserDetailsService#loadUserByUsername

in this method , return the userdetail object

问题:哪里调用setUserDetailsService?
上面一篇文章说的是fiter流程,其中最关键的是AbstractConfiguredSecurityBuilder#doBuild
这里有很多构建过程,其中一步是 BrowserSecurityConfig,即我们自定义的配置类初始化的过程,
org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter#init
->org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter#getHttp
->AuthenticationManager authenticationManager = authenticationManager();这里需要先构建AuthenticationManager对象
构建的过程也是调用AbstractConfiguredSecurityBuilder#doBuild 这里面的模板方法,不过初始化调用的是
org.springframework.boot.autoconfigure.security.AuthenticationManagerConfiguration.SpringBootAuthenticationConfigurerAdapter#init

==》这里会构建一个默认的对象
auth.apply(new AuthenticationManagerConfiguration.DefaultInMemoryUserDetailsManagerConfigurer(this.securityProperties))

==》之后调用 模板方法里面的
AbstractConfiguredSecurityBuilder#configure
InitializeUserDetailsBeanManagerConfigurer.InitializeUserDetailsManagerConfigurer#configure
UserDetailsService 以及加密方式PasswordEncoder 都在这里设置进来

public void configure(AuthenticationManagerBuilder auth) throws Exception {
			if (auth.isConfigured()) {
				return;
			}
			UserDetailsService userDetailsService = getBeanOrNull(
					UserDetailsService.class);
			if (userDetailsService == null) {
				return;
			}

			PasswordEncoder passwordEncoder = getBeanOrNull(PasswordEncoder.class);

			DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
			provider.setUserDetailsService(userDetailsService);
			if (passwordEncoder != null) {
				provider.setPasswordEncoder(passwordEncoder);
			}

			auth.authenticationProvider(provider);
		}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值