cas相关问题

Posted mmh760

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了cas相关问题相关的知识,希望对你有一定的参考价值。

上个礼拜搞安全问题,搞了几天,大部分是关于登录、账密、权限问题,现在做一个简单的总结

 

一,CAS

我这里是要在CAS里面做一个‘密码错误5次就锁定30分钟’。因为时刚拿到CAS,不太熟悉。问了一下同事,同事说好像CAS支持配置,不过,

在网上看了一下,好像是有配置,分单节点,和多节点。但是%#%¥¥……%*&……,然后我自己是实现。

一般来说,做这种需求,需要在数据库新增字段,例如‘最后登录时间’-->用来与锁定的时间对比,还有‘是否锁定’-->isLock

我所知道的是,CAS时直接用jdbcTemplate操作数据库的,在QueryDatabaseAuthenticationHandler 这里根据用户名查到密码(dbPassword),然后返回boolean值

 protected final boolean authenticateUsernamePasswordInternal(final UsernamePasswordCredentials credentials) throws AuthenticationException 
        final String username = getPrincipalNameTransformer().transform(credentials.getUsername());
        final String password = credentials.getPassword();
        final String encryptedPassword = this.getPasswordEncoder().encode(
            password);
        
        try 
            final String dbPassword = getJdbcTemplate().queryForObject(this.sql, String.class, username);
            return dbPassword.equals(encryptedPassword);
         catch (final IncorrectResultSizeDataAccessException e) 
            // this means the username was not found.
            return false;
        
    

也可以在这里查其他字段,因为是根据sql直接查的,所有要在deployerConfigContext.xml里面配一下sql

<bean  class="org.jasig.cas.adaptors.jdbc.QueryDatabaseAuthenticationHandler">
                   <property name="dataSource" ref="dataSource" />
                   <property name="sql" value="select password from p_user where username=?" />
//需要对象的话,先封装一个对象(但我还不知道CAS是咋映射到数据库的) <property name="passwordEncoder" ref="passwordEncoderBean"/> </bean>

如果使用数据库做这个需求的话,可以参考上面的

如果是用缓存做的话就简单多了,贴代码

 protected Pair<AuthenticationHandler, Principal> authenticateAndObtainPrincipal(final Credentials credentials) throws AuthenticationException 
        boolean foundSupported = false;
        boolean authenticated = false;
        AuthenticationHandler authenticatedClass = null;
        String handlerName;
        
        for (final AuthenticationHandler authenticationHandler : this.authenticationHandlers) 
            if (authenticationHandler.supports(credentials)) 
                foundSupported = true;
                handlerName = authenticationHandler.getClass().getName();
                try 
                    String username = ((UsernamePasswordCredentials) credentials).getUsername();
                    ValueOperations<String, String> valueOperations = redisTemplate.opsForValue();
                    // reached the threshold--->warning
                    String loginFailTimesKey = LOGIN_FAIL_TIMES + username;
                    //loginFailTimesKey > 5,loginFailFlagKey才有值
                    String loginFailFlagKey = LOGIN_FAIL_FLAG + username;
                    String failFlag = valueOperations.get(loginFailFlagKey);
                    if (StringUtils.isNotEmpty(failFlag)) 
                        throw OutBindAuthenticationException.ERROR;
                    
                    //!authenticationHandler.authenticate(credentials)去数据库校验用戶密碼
                    if (!authenticationHandler.authenticate(credentials)) 
                        //登录校验用户名密码失败
                        log.info(" failed to authenticate ", handlerName, credentials);
                        // redis operation 记录密码出错次数
                        if (valueOperations.get(loginFailTimesKey) == null) 
                            long milliSecondsLeftToday = 86400000 - DateUtils.getFragmentInMilliseconds(Calendar.getInstance(), Calendar.DATE);
                            //首次出错,记录为1
                            valueOperations.set(loginFailTimesKey, "1", milliSecondsLeftToday, TimeUnit.MILLISECONDS);
                         else 
                            //非首次出错,次数+1
                            valueOperations.increment(loginFailTimesKey, 1);
                        
                        //出错次数>5次 ,锁定30分钟
                        if (Long.valueOf(valueOperations.get(loginFailTimesKey)) >= 5) 
                            valueOperations.set(loginFailFlagKey, "1", 30, TimeUnit.MINUTES);
                        
                     else 
                        //登录成功
                        log.info(" successfully authenticated ", handlerName, credentials);
                        authenticatedClass = authenticationHandler;
                        authenticated = true;
                        //清除密碼錯誤次數緩存
                        redisTemplate.delete(loginFailTimesKey);
                        break;
                    
                 catch (final Exception e) 
                    handleError(handlerName, credentials, e);
                
            
        

casLoginView 这是前端页面,然后提交form表单数据到:AuthenticationViaFormAction,这里的submit方法是校验入口,然后再到QueryDatabaseAuthenticationHandler, 这个是从数据库拿值判断,然后再到AuthenticationManagerImpl 返回到这里,所以最终实现是在该类的authenticateAndObtainPrincipal方法里面,代码就在上面。

这里要提一下,我这个需求如果用户错5次,不允许其登录了,但是也要给个提示信息啊,所以这里我自定义了一个异常类OutBindAuthenticationException,如果用户错5次,

抛出该异常 throw OutBindAuthenticationException.ERROR;这里面的CODE,要在messages_zh_CN.properties里面定义,是ascII码。OK就这样

 

以上是关于cas相关问题的主要内容,如果未能解决你的问题,请参考以下文章

安装部署jasig cas server及相关实践

安装部署jasig cas server及相关实践

CAS锁相关讲解

SSO之CAS单点登录实例演示

单点登录系统CAS入门

AQS和CAS