CAS 구현 사이트 내 단일 로그인 및 타사 OAuth, OpenId 로그인(2)

11892 단어

1. 로그인 양식

<form:form id="loginForm" method="post" commandName="${commandName}" htmlEscape="true">
    <form:errors path="*" element="em" cssClass="" />
    <c:if test="${not empty sessionScope.openIdLocalId}">
         <input id="username" name="username" type="text" value="${sessionScope.openIdLocalId}" />
    </c:if>
    <c:if test="${empty sessionScope.openIdLocalId}">
        <!--   input,  springframework   form:input  ,  -->
        <form:input id="username" path="username" htmlEscape="true" />
    </c:if>
     :<input id="password" name="password" type="password" />
     :<input id="validateCode" name="validateCode" type="text" /><img src="/captcha.jpg" />
    <input id="rememberMe" name="rememberMe" type="checkbox" value="true" /><label for="rememberMe"> </label>
    <input id="login-Btn" type="button" value=" " />
    <input name="lt" type="hidden" value="${loginTicket}" />
    <input name="execution" type="hidden" value="${flowExecutionKey}" />
    <input name="_eventId" type="hidden" value="submit" />
</form:form>
<!--   jquery.cookie   jquery.md5   -->
<script type="text/javascript">
    $(document).ready(function(){
        var loginUsername = $.cookie("loginUsername");
        if(loginUsername){
            $("#username").val(loginUsername);
            $("#rememberMe").attr("checked", true);
        }
        $("#login-Btn").click(function(){
            /*  , ,  md5   */
            $("#password").val($.md5($("#password").val()));
            if($("#rememberMe").is(":checked") == true){
                $.cookie("loginUsername", $("#username").val(), {expires: 365});
            }else{
                $.cookie("loginUsername", null, {expires: -1});
            }
            $("#loginForm").submit();
        });
    });
</script>

2. 인증번호


이 예에서 검증은 Google의 Kaptcha를 사용합니다.
  • Google Kaptcha 구성(WEB-INF/spring-configuration/applicationContext.xml 추가)
    <bean id="captchaConfig" class="com.google.code.kaptcha.util.Config">
        ... ...
    </bean>
    <bean id="captchaProducer" class="com.google.code.kaptcha.impl.DefaultKaptcha" p:config-ref="captchaConfig" />
  • Servlet 구성 1) WEB-INF/cas-servlet 수정.xml의
    <bean id="authenticationViaFormAction" class="org.jasig.cas.web.flow.AuthenticationViaFormAction"
            p:centralAuthenticationService-ref="centralAuthenticationService"
            p:warnCookieGenerator-ref="warnCookieGenerator"/>
    : AuthenticationCaptchaViaForm Action.java(사용자 검증 액션)
    <bean id="authenticationViaFormAction" class="com.buession.cas.web.flow.AuthenticationCaptchaViaFormAction"
            p:captchaConfig-ref="captchaConfig"
            p:centralAuthenticationService-ref="centralAuthenticationService"
            p:warnCookieGenerator-ref="warnCookieGenerator" />
    2)는 WEB-INF/cas-servlet에 있습니다.xml CaptchaController 추가.java Validate Captcha Controller.java(인증 코드 비동기 검증 컨트롤러)
    <bean id="handlerMappingC" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
        <property name="mappings">
            <props>
                <prop key="/captcha.jpg">captchaController</prop><!--   Controller -->
                <prop key="/validateCaptcha">validateCaptchaController</prop><!--   Controller,  -->
                ... ...
            </props>
        </property>
    </bean>
    <bean id="captchaController" class="com.buession.cas.web.controller.CaptchaController"
        p:config-ref="captchaConfig" />
    <bean id="validateCaptchaController" class="com.buession.cas.web.controller.ValidateCaptchaController" 
        p:config-ref="captchaConfig" />
    3) 웹에서 기억하세요.xml Servlet 및 URL 간 매핑 추가
  • 3. 사용자 인증

  • 데이터베이스 설정(WEB-INF/spring-configuration/applicationContext.xml 추가)
    <bean id="masterJdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"
        p:dataSource-ref="masterDataSource" />
    <bean id="slaveJdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"
        p:dataSource-ref="slaveDataSource" />
    
    <bean id="masterDataSource" class="org.apache.commons.dbcp.BasicDataSource"
        ... ...
        destroy-method="close" />
    <bean id="slaveDataSource" class="org.apache.commons.dbcp.BasicDataSource"
        ... ...
        destroy-method="close" />
    master 데이터 원본과slave 데이터 원본을 왜 설정합니까?사용자가 로그인할 때 사용자 정보를 조회하는 것은 읽기 전용이다. 우리는 라이브러리에서 조회한다. 메인 라이브러리는 데이터베이스에 사용자 로그인 로그를 쓰거나 비밀번호 오류 횟수를 기록할 수 있다. (물론 이것은 실제 수요에 따라 조정할 수 있다. 예를 들어 사용자 비밀번호 입력 오류 횟수, 또는 Memcache, Redis 등 캐시 서버에 기록할 수 있다)
  • 사용자 자격 증명 수정credentials(WEB-INF/login-webflow.xml) 수정
    <var name="credentials" class="org.jasig.cas.authentication.principal.UsernamePasswordCredentials" />
    : RememberMeUsernamePasswordCaptchaCredentials.java(RememberMe 및 인증 코드가 있는 사용자 인증서)
    <var name="credentials" class="com.buession.cas.authentication.principal.RememberMeUsernamePasswordCaptchaCredentials" />
  • AuthenticationViaForm Action(WEB-INF/login-webflow.xml) 수정
    <view-state id="viewLoginForm" view="casLoginView" model="credentials">
        <binder>
            <binding property="username" />
            <binding property="password" />
        </binder>
        ... ...
    </view-state>
    (binding의property 속성 값은 반드시 Credentials의 속성 이름과 로그인 폼 컨트롤의name 속성 값과 일치해야 함)
    <view-state id="viewLoginForm" view="casLoginView" model="credentials">
        <binder>
            <binding property="username" />
            <binding property="password" />
            <binding property="validateCode" />
        </binder>
        ... ...
    </view-state>
  • 데이터베이스 authentication handlers 추가(WEB-INF/deployerConfigContext.xml에 추가)
    <bean id="authenticationManager" class="org.jasig.cas.authentication.AuthenticationManagerImpl">
        ... ...
        <property name="authenticationHandlers">
            <list>
                <bean class="com.domain.authentication.handler.DatabaseAuthenticationHandler">
                    <property name="jdbcTemplate" ref="slaveJdbcTemplate" />
                    <!--(1)--><property name="sql" value="SELECT `password`, `salt`, `algo` FROM `member` WHERE `username` = ? LIMIT 1" />
                    <!--(2)--><property name="sql" value="SELECT `password`, `salt`, `algo` FROM `member` WHERE `username` = ? OR `email` = ? OR `mobile` = ? LIMIT 1" />
                    <!--(3)--><property name="sql" value="SELECT `password`, `salt`, `algo` FROM `member` WHERE `username` = ? OR `email` = ? OR `mobile` = ?" />
                    <!-- (1) ;(2) , ;(3) , , :  username  :13800138000,  mobile  :13800138000   -->
                    <property name="passwordEncoder" ref="passwordEncoder" />
                </bean>
            </list>
        </property>
    </bean>
    class DatabaseAuthenticationHandler extends com.buession.cas.authentication.handler.support.DatabaseQueryAuthenticationHandler {
    
        @Override
        protected boolean authenticateUsernamePasswordInternal(UsernamePasswordCredentials credentials)
                throws AuthenticationException {
            PasswordEncoder passwordEncoder = (PasswordEncoder) getPasswordEncoder();
            String username = getPrincipalNameTransformer().transform(credentials.getUsername());
            String password = credentials.getPassword();
    
            (1)、(2)
            try {
                final Map<String, Object> r = jdbcTemplate.queryForMap(sql, username, username,
                        username);
                if (valid(username, password, r, passwordEncoder) == true) {
                     /**
                       *  , 
                     */
                    if (Mcrypt.MD5.equals(r.get("algo")) == true) {
                        modifyEncoder((String) r.get("username"), credentials.getPassword(),
                                (String) r.get("salt"));
                    }
                    return ture;
                }
            } catch (IncorrectResultSizeDataAccessException e) {
            }
    
            (3)
            try {
                List<Map<String, Object>> result = jdbcTemplate.queryForList(sql, username, username,
                        username);
    
                if (result != null && result.size() > 0) {
                    for (Map<String, Object> r : result) {
                        if (valid(username, password, r, passwordEncoder) == true) {
                            /**
                             *  , 
                             */
                            if (Mcrypt.MD5.equals(r.get("algo")) == true) {
                                modifyEncoder((String) r.get("username"), credentials.getPassword(),
                                        (String) r.get("salt"));
                            }
                            return true;
                        }
                    }
                }
            } catch (IncorrectResultSizeDataAccessException e) {
            }
    
            return false;
        }
    
        private boolean valid(String username, String password, final Map<String, Object> object,
                PasswordEncoder passwordEncoder) {
            String salt = (String) object.get("salt");
            String algo = (String) object.get("algo");
    
            passwordEncoder.setAlgo(algo);
    
            /**
             *   "MD5", 
             *  , ,  MD5  ,
             *   MD5  , ,  encode(password+salt)
             */
            if (Mcrypt.MD5.equals(algo) == true) {
                password += salt;
            } else {
                passwordEncoder.setSalt(salt);
            }
    
            final String encodedPassword = passwordEncoder.encode(password);
            return encodedPassword != null && encodedPassword.equalsIgnoreCase((String) object.get("password"));
        }
    
        private void modifyEncoder(final String username, final String password, final String salt) {
            PasswordEncoder passwordEncoder = (PasswordEncoder) getPasswordEncoder();
    
            passwordEncoder.setAlgo(Mcrypt.SHA512);
            passwordEncoder.setSalt(salt);
    
            String sql = "UPDATE `member` SET `algo` = ?, `password` = ? WHERE `username` = ?";
            jdbcTemplate.update(sql, Mcrypt.SHA512, passwordEncoder.encode(password), username);
        }
    }
  • 암호 암호화 구성(WEB-INF/deployerConfigContext.xml 추가)
    <bean id="passwordEncoder" class="com.buession.cas.authentication.handler.PasswordEncoder"
        p:characterEncoding="UTF-8" />
    PasswordEncoder.java
  • 인증 코드 인증 메시지 추가(WEB-INF/classes/messages_xx.properties)
    required.captcha= 
    INVALID_CAPTCHA= 
  • 좋은 웹페이지 즐겨찾기