一 Spring Security比较好的教程
http://www.spring4all.com/article/428
二 基于数据库的密码认证
http://www.spring4all.com/article/420
三 该项目github地址
https://github.com/cakin24/spring-security-demos
四 先演示项目,再讲解原理
1 按照 https://github.com/cakin24/spring-security-demos/tree/master/00%20-%20%E6%B3%A8%E5%86%8C%E7%99%BB%E5%BD%95%EF%BC%88%E6%95%B0%E6%8D%AE%E5%BA%93%EF%BC%89的使用手册先将环境搭建起来
2 启动项目
3 注册用户
http://localhost:8080/register
用户名:admin
密码:admin
注册后数据库中的数据
4 用刚注册的用户去登录
登录可以成功。
五 原理解释
到底是在Spring Security哪一块进行的密码验证呢?
其实主要是两个用户数据获取和一个比较。
第一个用户数据获取:从浏览器输入的用户和密码,用户名和密码会传递到Spring Security内部。
第二个用户数据获取:根据用户名从数据库获得用户详情。
一个比较:将前面两个数据获取进行比较,匹配则通过验证,否则验证不通过。
两个用户数据获取:http://www.spring4all.com/article/420 这篇博客写的很清楚
下面看看是哪里进行的密码比较
1 /spring-security-core-5.1.4.RELEASE-sources.jar!/org/springframework/security/authentication/dao/AbstractUserDetailsAuthenticationProvider.java
public Authentication authenticate(Authentication authentication) // 重点关注这个函数,不重要先略去
throws AuthenticationException {
......
try {
preAuthenticationChecks.check(user);
// 重点看这个地方,additionalAuthenticationChecks这个函数会被DaoAuthenticationProvider实现。所以我们要看看DaoAuthenticationProvider的additionalAuthenticationChecks函数实现
additionalAuthenticationChecks(user,(UsernamePasswordAuthenticationToken) authentication);
}
catch (AuthenticationException exception) {
if (cacheWasUsed) {
// There was a problem, so try again after checking
// we're using latest data (i.e. not from the cache)
cacheWasUsed = false;
user = retrieveUser(username,
(UsernamePasswordAuthenticationToken) authentication);
preAuthenticationChecks.check(user);
additionalAuthenticationChecks(user,
(UsernamePasswordAuthenticationToken) authentication);
}
else {
throw exception;
}
}
postAuthenticationChecks.check(user);
......
return createSuccessAuthentication(principalToReturn, authentication, user);
}
2 /spring-security-core-5.1.4.RELEASE-sources.jar!/org/springframework/security/authentication/dao/DaoAuthenticationProvider.java
protected void additionalAuthenticationChecks(UserDetails userDetails,
UsernamePasswordAuthenticationToken authentication)
throws AuthenticationException {
if (authentication.getCredentials() == null) {
logger.debug("Authentication failed: no credentials provided");
throw new BadCredentialsException(messages.getMessage(
"AbstractUserDetailsAuthenticationProvider.badCredentials",
"Bad credentials"));
}
String presentedPassword = authentication.getCredentials().toString();
// 密码比较就在这个地方,前面这个是用户输入的密码,后面这个是数据库存的密码,一致则通过
if (!passwordEncoder.matches(presentedPassword, userDetails.getPassword())) {
logger.debug("Authentication failed: password does not match stored value");
throw new BadCredentialsException(messages.getMessage(
"AbstractUserDetailsAuthenticationProvider.badCredentials",
"Bad credentials"));
}
}
通过这两步分析,应该很清楚了吧。