zoukankan      html  css  js  c++  java
  • 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就这样

  • 相关阅读:
    OpenStack开发基础-oslo.config
    对象的封装
    Oracle动态显示日志
    Marching squares &amp; Marching cubes
    Keil5.15使用GCC编译器链接.a库文件
    数据结构习题之树
    HDU 5358(2015多校联合训练赛第六场1006) First One (区间合并+常数优化)
    使用URL在线语音合成
    企业怎样高速搭建大数据处理系统
    http://blog.sina.com.cn/s/blog_7caae74b0100zl17.html
  • 原文地址:https://www.cnblogs.com/mmh760/p/11063762.html
Copyright © 2011-2022 走看看