CAS开始看源码了
源码熟悉
从AbstractPreAndPostProcessingAuthenticationHandler.authenticate开始:
先看一下Credential
接口,我们再看下实现类:
这么多实现类,选一个用户名密码的看吧:
有点像http请求里的request,姑且先当成request看吧
再回过来看AbstractPreAndPostProcessingAuthenticationHandler
if()里形同虚置
重点在doAuthentication(Credential)里
这个方法也有一些实现类,老规矩,还是看用户名密码的那个实现类:
AbstractUsernamePasswordAuthenticationHandler.doAuthentication
protected AuthenticationHandlerExecutionResult doAuthentication(final Credential credential) throws GeneralSecurityException, PreventedException {
//1、
final UsernamePasswordCredential originalUserPass = (UsernamePasswordCredential) credential;
final UsernamePasswordCredential userPass = new UsernamePasswordCredential(originalUserPass.getUsername(), originalUserPass.getPassword());
if (StringUtils.isBlank(userPass.getUsername())) {
throw new AccountNotFoundException("Username is null.");
}
LOGGER.debug("Transforming credential username via [{}]", this.principalNameTransformer.getClass().getName());
//2、
final String transformedUsername = this.principalNameTransformer.transform(userPass.getUsername());
if (StringUtils.isBlank(transformedUsername)) {
throw new AccountNotFoundException("Transformed username is null.");
}
if (StringUtils.isBlank(userPass.getPassword())) {
throw new FailedLoginException("Password is null.");
}
3、
LOGGER.debug("Attempting to encode credential password via [{}] for [{}]", this.passwordEncoder.getClass().getName(),
transformedUsername);
final String transformedPsw = this.passwordEncoder.encode(userPass.getPassword());
if (StringUtils.isBlank(transformedPsw)) {
throw new AccountNotFoundException("Encoded password is null.");
}
userPass.setUsername(transformedUsername);
userPass.setPassword(transformedPsw);
LOGGER.debug("Attempting authentication internally for transformed credential [{}]", userPass);
return authenticateUsernamePasswordInternal(userPass, originalUserPass.getPassword());
}
看标记的流程符号
1、转换,将Credential转化为UsernamePasswordCredential,UsernamePasswordCredential是Credential的实现,上面已经看过了,里面是username和password,值得一提,里面有个getId()返回的是username。
2、对用户名做处理,不注入的话,是原样返回:
private PrincipalNameTransformer principalNameTransformer = formUserId -> formUserId;
3、密码解密
4、调用authenticateUsernamePasswordInternal方法进行验证凭证
接下来就要去这个方法了
由于这个方法是未实现的,老规矩,继续随便找一个实现看流程:
QueryDatabaseAuthenticationHandler.authenticateUsernamePasswordInternal
这个方法比较简单:
protected AuthenticationHandlerExecutionResult authenticateUsernamePasswordInternal(final UsernamePasswordCredential credential, final String originalPassword) throws GeneralSecurityException, PreventedException {
if (!StringUtils.isBlank(this.sql) && this.getJdbcTemplate() != null) {
Map<String, Object> attributes = new LinkedHashMap(this.principalAttributeMap.size());
String username = credential.getUsername();
String password = credential.getPassword();
try {
Map<String, Object> dbFields = this.query(credential);
String dbExpired;
if (!dbFields.containsKey(this.fieldPassword)) {
LOGGER.debug("Password field is not found in the query results. Checking for result count...");
if (!dbFields.containsKey("total")) {
throw new FailedLoginException("Missing field 'total' from the query results for " + username);
}
Object count = dbFields.get("total");
if (count == null || !NumberUtils.isCreatable(count.toString())) {
throw new FailedLoginException("Missing field value 'total' from the query results for " + username + " or value not parseable as a number");
}
Number number = NumberUtils.createNumber(count.toString());
if (number.longValue() != 1L) {
throw new FailedLoginException("No records found for user " + username);
}
} else {
dbExpired = (String)dbFields.get(this.fieldPassword);
if (StringUtils.isNotBlank(originalPassword) && !this.matches(originalPassword, dbExpired) || StringUtils.isBlank(originalPassword) && !StringUtils.equals(password, dbExpired)) {
throw new FailedLoginException("Password does not match value on record.");
}
}
if (StringUtils.isNotBlank(this.fieldDisabled) && dbFields.containsKey(this.fieldDisabled)) {
dbExpired = dbFields.get(this.fieldDisabled).toString();
if (BooleanUtils.toBoolean(dbExpired) || "1".equals(dbExpired)) {
throw new AccountDisabledException("Account has been disabled");
}
}
if (StringUtils.isNotBlank(this.fieldExpired) && dbFields.containsKey(this.fieldExpired)) {
dbExpired = dbFields.get(this.fieldExpired).toString();
if (BooleanUtils.toBoolean(dbExpired) || "1".equals(dbExpired)) {
throw new AccountPasswordMustChangeException("Password has expired");
}
}
this.collectPrincipalAttributes(attributes, dbFields);
} catch (IncorrectResultSizeDataAccessException var9) {
if (var9.getActualSize() == 0) {
throw new AccountNotFoundException(username + " not found with SQL query");
}
throw new FailedLoginException("Multiple records found for " + username);
} catch (DataAccessException var10) {
throw new PreventedException("SQL exception while executing query for " + username, var10);
}
Principal principal = this.principalFactory.createPrincipal(username, attributes);
return this.createHandlerResult(credential, principal, new ArrayList(0));
} else {
throw new GeneralSecurityException("Authentication handler is not configured correctly. No SQL statement or JDBC template is found.");
}
}
拿到用户名密码去数据库里进行查询,然后对结果一系列的判断,略过,继续看调用 collectPrincipalAttributes:
总的来说就是遍历principalAttributeMap,在dbFields找有没有这个key,有的话将dbFields的值填到principalAttributeMa里去。
现在值也找到了,也填充完了,接下来就是创建Principal ,principalFactory.createPrincipal();
看完第一个实现继续看第二个:QueryAndEncodeDatabaseAuthenticationHandler
这个雨上一个的区别在于:密码有加密处理,登录有时限判断,账户有判断
上面这两个都是从数据库里查用户信息的,接下来换一个方向继续来ClientAuthenticationHandler:
可以看到这个有基于pac4j框架的,对这个不理解的可以去补补课
protected AuthenticationHandlerExecutionResult doAuthentication(final Credential credential) throws GeneralSecurityException, PreventedException {
try {
//1、
ClientCredential clientCredentials = (ClientCredential)credential;
LOGGER.debug("Located client credentials as [{}]", clientCredentials);
Credentials credentials = clientCredentials.getCredentials();
LOGGER.debug("Client name: [{}]", clientCredentials.getClientName());
BaseClient client = (BaseClient)this.clients.findClient(clientCredentials.getClientName());
LOGGER.debug("Delegated client is: [{}]", client);
if (client == null) {
throw new IllegalArgumentException("Unable to determine client based on client name " + clientCredentials.getClientName());
} else {
//2、
HttpServletRequest request = WebUtils.getHttpServletRequestFromExternalWebflowContext();
HttpServletResponse response = WebUtils.getHttpServletResponseFromExternalWebflowContext();
WebContext webContext = Pac4jUtils.getPac4jJ2EContext(request, response);
UserProfile userProfile = client.getUserProfile(credentials, webContext);
LOGGER.debug("Final user profile is: [{}]", userProfile);
return this.createResult(clientCredentials, userProfile, client);
}
} catch (HttpAction var9) {
throw new PreventedException(var9);
}
}
1、转化为ClientCredential
2、获取用户信息UserProfile
疑惑点:
按代码的意思,AuthorizationGenerator只会取到最后一个
上一篇: 深入剖析Java中的锁【原理、锁优化、CAS、AQS】
下一篇: GET和POST的真正区别