前言
刚开始学习spring security的时候认证用户的信息来源是在配置文件中配置,然后加载到内存中来实现用户的认证的,但是,在我们的实际项目中用户的信息不可能通过配置文件来配置的,这样很繁琐而且又不安全,所以,这些信息要通过一个落地操作把它们存储起来,这样分开操作也符合了软件设计思想,同时也便于维护,那么我们应该通过怎样的方式来实现自定义方式的数据库认证呢,下面通过来分析认证流程来实现我们想要的方式。
源码分析
首先我们知道spring security的实现是通过一个个的filter来实现的,这里提一下filter的实现原理是基于函数回调来实现的。
函数回调其实简单讲就是,FilterChain作为参数传递给了xxFilter的doFilter()方法,然后在该方法中又调用了FilterChain的doFilter()方法。
所以,我们先看一下负责认证的过滤器UsernamePasswordAuthenticationFilter,从那里看起呢,filter相关的类首先看dofilter方法,这个类的dofilter方法在父类中
在上面的这段代码中进行认证,点击attemptAuthentication进入到子类UsernamePasswordAuthenticationFilter的attemptAuthentication方法中
点击上面最后一段代码的authenticate进入到AuthenticationManager接口中的,然后看接口的实现类ProviderManager的authenticate方法
我们继续点击provider.authenticate(authentication)这一段代码的authenticate方法,进入到AuthenticationProvider的实现类AbstractUserDetailsAuthenticationProvider
我们点击上面的retrieveUser方法进入到实现类DaoAuthenticationProvider中的retrieveUser方法里面
我们点击下面loadUserByUsername方法进入到的是UserDetailsService这个接口中,所以说我们可以直接写一个UserDetailsService的实现类,然后在loadUserByUsername方法中返回我们数据库中用户信息来源就可以了,同样也把查到的用户信息来源封装成UserDetails对象进行返回即可。
最后在顺便提一下认证成功和失败之后的操作,这里可以看一下AbstractAuthenticationProcessingFilter这个类的dofilter方法
在上面认证成功之前还有一个操作就是会将认证用户的权限集合设置进来,还有会设置一个是否认证的字段为true,我们可以看一下认证的AuthenticationProvider实现类AbstractUserDetailsAuthenticationProvider的authenticate方法最后一行代码createSuccessAuthentication(principalToReturn, authentication, user),点击进入
然后继续点击UsernamePasswordAuthenticationToken类,可以看到两个构造方法,一个是认证之前的,一个是认证成功之后的,下面这个下认证成功之后的
父类AbstractAuthenticationToken构造方法,会将权限设置进来