SpringSecurity是在拦截器Interceptor前面的。
SpringSecurity走完,如果项目中设置了拦截器,还会走拦截器的。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
添加依赖后,启动项目,访问任意接口都会跳转到登录页
输入账号,密码,程序会先执行到UsernamePasswordAuthenticationFilter
的attemptAuthentication方法
// UsernamePasswordAuthenticationFilter.class
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response){
if (this.postOnly && !request.getMethod().equals("POST")) {
throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
} else {
String username = this.obtainUsername(request); // 从HttpServletRequest中拿到传来的的用户名参数
username = username != null ? username : "";
username = username.trim();
String password = this.obtainPassword(request); // 从HttpServletRequest中拿到传来的的密码参数
password = password != null ? pasword : "";
// 封装 Authentication
UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password);
this.setDetails(request, authRequest);
return this.getAuthenticationManager().authenticate(authRequest); // 试图认证
}
}
进入到ProviderManager
这个类当中的authenticate方法。
之后调用DaoAuthenticationProvider
继承的其父类public abstract class AbstractUserDetailsAuthenticationProvider
的authenticate方法。
之后进入到DaoAuthenticationProvider
这个类中retrieveUser方法。
protected final UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication) {
this.prepareTimingAttackProtection();
try { // 根据用户名在系统中查询用户信息
UserDetails loadedUser = this.getUserDetailsService().loadUserByUsername(username);
if (loadedUser == null) {
throw new InternalAuthenticationServiceException("UserDetailsService returned null, which is an interface contract violation");
} else {
return loadedUser;
}
} catch (Exception var6) {
throw new InternalAuthenticationServiceException(var6.getMessage(), var6);
}
}
之后又进入到public class InMemoryUserDetailsManager implements UserDetailsManager, UserDetailsPasswordService
这个类中的loadUserByUsername方法
public UserDetails loadUserByUsername(String username){
// 根据用户名在系统中查询用户信息
// InMemory是默认内存中存着相应的用户信息
UserDetails user = (UserDetails)this.users.get(username.toLowerCase());
if (user == null) {
throw new UsernameNotFoundException(username);
} else {
// 封装返回
return new User(user.getUsername(), user.getPassword(), user.isEnabled(),
user.isAccountNonExpired(), user.isCredentialsNonExpired(),
user.isAccountNonLocked(), user.getAuthorities());
}
}
查询到的话,封装为UserDetails,又层层返回至AbstractUserDetailsAuthenticationProvider
类中的authenticate方法。
之后又进入到DaoAuthenticationProvider
类中的additionalAuthenticationChecks方法。
// userDetails是在系统中查到的用户信息, authentication是登录时填写的信息进行封装
protected void additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken authentication){
if (authentication.getCredentials() == null) {
this.logger.debug("Failed to authenticate since no credentials provided");
throw new BadCredentialsException(this.messages
.getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"));
} else {
// 比对密码
String presentedPassword = authentication.getCredentials().toString();
if (!this.passwordEncoder.matches(presentedPassword, userDetails.getPassword())) {
this.logger.debug("Failed to authenticate since password does not match stored value");
throw new BadCredentialsException(this.messages
.getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"));
}
}
}
比对成功之后,又返回到AbstractUserDetailsAuthenticationProvider
类中的authenticate方法,调用DaoAuthenticationProvider
类中的createSuccessAuthentication方法
将从系统中查到的UserDetails信息(改名为principal),以及authentication(用户登陆时填的信息),以及一个MutableUserDetails(将从系统中查到的UserDetails信息,将其中的密码进行Bcrpt加密,封装为MutableUserDetails对象)这三者进行整合,最后封装信息,返回一个UsernamePasswordAuthenticationToken。