欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

CAS开始看源码了

程序员文章站 2022-05-04 15:49:52
...

源码熟悉

从AbstractPreAndPostProcessingAuthenticationHandler.authenticate开始:
CAS开始看源码了
先看一下Credential
CAS开始看源码了

接口,我们再看下实现类:
CAS开始看源码了

这么多实现类,选一个用户名密码的看吧:
CAS开始看源码了
有点像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:
CAS开始看源码了

总的来说就是遍历principalAttributeMap,在dbFields找有没有这个key,有的话将dbFields的值填到principalAttributeMa里去。
现在值也找到了,也填充完了,接下来就是创建Principal ,principalFactory.createPrincipal();

看完第一个实现继续看第二个:QueryAndEncodeDatabaseAuthenticationHandler
这个雨上一个的区别在于:密码有加密处理,登录有时限判断,账户有判断
CAS开始看源码了

上面这两个都是从数据库里查用户信息的,接下来换一个方向继续来ClientAuthenticationHandler:
可以看到这个有基于pac4j框架的,对这个不理解的可以去补补课
CAS开始看源码了

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
CAS开始看源码了

2、获取用户信息UserProfile
CAS开始看源码了

疑惑点:
CAS开始看源码了
CAS开始看源码了

按代码的意思,AuthorizationGenerator只会取到最后一个

相关标签: CAS java