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只会取到最后一个

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值