zoukankan      html  css  js  c++  java
  • cas4.2.4 登添加验证码

    看了很多添加验证码的博文,唯独没有4.24的 重点看第3条,其余的和别人博文大致相同

    1.首先在cas工程的web.xml增加验证码功能的支持

        <!-- 验证码功能 -->  
        <servlet>  
            <servlet-name>Kaptcha</servlet-name>  
            <servlet-class>com.google.code.kaptcha.servlet.KaptchaServlet</servlet-class>  
            <init-param>  
                <param-name>kaptcha.border</param-name>  
                <param-value>no</param-value>  
            </init-param>  
            <init-param>  
                <param-name>kaptcha.textproducer.char.space</param-name>  
                <param-value>5</param-value>  
            </init-param>  
            <init-param>  
                <param-name>kaptcha.textproducer.char.length</param-name>  
                <param-value>5</param-value>  
            </init-param>  
        </servlet>  
          
        <servlet-mapping>  
            <servlet-name>Kaptcha</servlet-name>  
            <url-pattern>/captcha.jpg</url-pattern>  
        </servlet-mapping>  
        
    2.新建一个类UsernamePasswordCredentialWithAuthCode,该类继承了

    org.jasig.cas.authentication.UsernamePasswordCredential,添加一个验证码字段,

    并且重写equals和hashCode方法,添加关于验证码比较的信息

    package org.jasig.cas.web.flow;

    import javax.validation.constraints.NotNull;
    import javax.validation.constraints.Size;

    import org.apache.commons.lang3.builder.HashCodeBuilder;
    import org.jasig.cas.authentication.UsernamePasswordCredential;

    public class UsernamePasswordCredentialWithAuthCode extends  
            UsernamePasswordCredential {  
        /** 
         * 带验证码的登录界面 
         */  
        private static final long serialVersionUID = 1L;  
        /** 验证码*/  
        @NotNull  
        @Size(min = 1, message = "required.authcode")  
        private String authcode;  
      
        /** 
         *  
         * @return 
         */  
        public final String getAuthcode() {  
            return authcode;  
        }  
      
        /** 
         *  
         * @param authcode 
         */  
        public final void setAuthcode(String authcode) {  
            this.authcode = authcode;  
        }  
      
        
        public UsernamePasswordCredentialWithAuthCode() {
            super();
        }

        public UsernamePasswordCredentialWithAuthCode(String userName,
                String password) {
            super(userName, password);
        }

        @Override  
        public boolean equals(final Object o) {  
            if (this == o) {  
                return true;  
            }  
            if (o == null || getClass() != o.getClass()) {  
                return false;  
            }  
      
            final UsernamePasswordCredentialWithAuthCode that = (UsernamePasswordCredentialWithAuthCode) o;  
      
            if (getPassword() != null ? !getPassword().equals(that.getPassword())  
                    : that.getPassword() != null) {  
                return false;  
            }  
      
            if (getPassword() != null ? !getPassword().equals(that.getPassword())  
                    : that.getPassword() != null) {  
                return false;  
            }  
            if (authcode != null ? !authcode.equals(that.authcode)  
                    : that.authcode != null)  
                return false;  
      
            return true;  
        }  
      
        @Override  
        public int hashCode() {  
            return new HashCodeBuilder().append(getUsername())  
                    .append(getPassword()).append(authcode).toHashCode();  
        }  
      
    }  

    3.新建一个类AuthenticationViaFormAction类,必须写在org.jasig.cas.web.flow包中,原因我是修改源码,红色为添加代码:这样做的原因是因为我实在无法找到去哪里配置bean,看他源码是注解,我配上注解也不管用,也懒得去研究,就这样弄吧!

    package org.jasig.cas.web.flow;

    import org.apache.commons.lang3.StringUtils;
    import org.jasig.cas.CasProtocolConstants;
    import org.jasig.cas.CentralAuthenticationService;
    import org.jasig.cas.authentication.AuthenticationContext;
    import org.jasig.cas.authentication.AuthenticationContextBuilder;
    import org.jasig.cas.authentication.AuthenticationException;
    import org.jasig.cas.authentication.AuthenticationSystemSupport;
    import org.jasig.cas.authentication.AuthenticationTransaction;
    import org.jasig.cas.authentication.Credential;
    import org.jasig.cas.authentication.DefaultAuthenticationContextBuilder;
    import org.jasig.cas.authentication.DefaultAuthenticationSystemSupport;
    import org.jasig.cas.authentication.HandlerResult;
    import org.jasig.cas.authentication.MessageDescriptor;
    import org.jasig.cas.authentication.RootCasException;
    import org.jasig.cas.authentication.principal.Service;
    import org.jasig.cas.ticket.AbstractTicketException;
    import org.jasig.cas.ticket.ServiceTicket;
    import org.jasig.cas.ticket.TicketCreationException;
    import org.jasig.cas.ticket.TicketGrantingTicket;
    import org.jasig.cas.web.support.WebUtils;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.binding.message.MessageBuilder;
    import org.springframework.binding.message.MessageContext;
    import org.springframework.stereotype.Component;
    import org.springframework.web.util.CookieGenerator;
    import org.springframework.webflow.core.collection.LocalAttributeMap;
    import org.springframework.webflow.execution.Event;
    import org.springframework.webflow.execution.RequestContext;

    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpSession;
    import javax.validation.constraints.NotNull;

    import Java.util.Map;

    /**
     * Action to authenticate credential and retrieve a TicketGrantingTicket for
     * those credential. If there is a request for renew, then it also generates
     * the Service Ticket required.
     *
     * @author Scott Battaglia
     * @since 3.0.0
     */
    @Component("authenticationViaFormAction")
    public class AuthenticationViaFormAction {

        /** Authentication succeeded with warnings from authn subsystem that should be displayed to user. */
        public static final String SUCCESS_WITH_WARNINGS = "successWithWarnings";

        /** Authentication failure result. */
        public static final String AUTHENTICATION_FAILURE = "authenticationFailure";


        /** Flow scope attribute that determines if authn is happening at a public workstation. */
        public static final String PUBLIC_WORKSTATION_ATTRIBUTE = "publicWorkstation";

        /** Logger instance. **/
        protected final transient Logger logger = LoggerFactory.getLogger(getClass());

        /** Core we delegate to for handling all ticket related tasks. */
        @NotNull
        @Autowired
        @Qualifier("centralAuthenticationService")
        private CentralAuthenticationService centralAuthenticationService;

        @NotNull
        @Autowired
        @Qualifier("warnCookieGenerator")
        private CookieGenerator warnCookieGenerator;

        @NotNull
        @Autowired(required=false)
        @Qualifier("defaultAuthenticationSystemSupport")
        private AuthenticationSystemSupport authenticationSystemSupport = new DefaultAuthenticationSystemSupport();

        /**
         * Handle the submission of credentials from the post.
         *
         * @param context the context
         * @param credential the credential
         * @param messageContext the message context
         * @return the event
         * @since 4.1.0
         */
        public final Event submit(final RequestContext context, final Credential credential,
                                  final MessageContext messageContext)  {
            if (isRequestAskingForServiceTicket(context)) {
                return grantServiceTicket(context, credential);
            }

            return createTicketGrantingTicket(context, credential, messageContext);
        }

        /**
         * Is request asking for service ticket?
         *
         * @param context the context
         * @return true, if both service and tgt are found, and the request is not asking to renew.
         * @since 4.1.0
         */
        protected boolean isRequestAskingForServiceTicket(final RequestContext context) {
            final String ticketGrantingTicketId = WebUtils.getTicketGrantingTicketId(context);
            final Service service = WebUtils.getService(context);
            return (StringUtils.isNotBlank(context.getRequestParameters().get(CasProtocolConstants.PARAMETER_RENEW))
                    && ticketGrantingTicketId != null
                    && service != null);
        }

        /**
         * Grant service ticket for the given credential based on the service and tgt
         * that are found in the request context.
         *
         * @param context the context
         * @param credential the credential
         * @return the resulting event. Warning, authentication failure or error.
         * @since 4.1.0
         */
        protected Event grantServiceTicket(final RequestContext context, final Credential credential) {
            final String ticketGrantingTicketId = WebUtils.getTicketGrantingTicketId(context);
            try {
                final Service service = WebUtils.getService(context);
                final AuthenticationContextBuilder builder = new DefaultAuthenticationContextBuilder(
                        this.authenticationSystemSupport.getPrincipalElectionStrategy());
                final AuthenticationTransaction transaction =
                        AuthenticationTransaction.wrap(credential);
                this.authenticationSystemSupport.getAuthenticationTransactionManager().handle(transaction,  builder);
                final AuthenticationContext authenticationContext = builder.build(service);

                final ServiceTicket serviceTicketId = this.centralAuthenticationService.grantServiceTicket(
                        ticketGrantingTicketId, service, authenticationContext);
                WebUtils.putServiceTicketInRequestScope(context, serviceTicketId);
                WebUtils.putWarnCookieIfRequestParameterPresent(this.warnCookieGenerator, context);
                return newEvent(AbstractCasWebflowConfigurer.TRANSITION_ID_WARN);

            } catch (final AuthenticationException e) {
                return newEvent(AUTHENTICATION_FAILURE, e);
            } catch (final TicketCreationException e) {
                logger.warn("Invalid attempt to access service using renew=true with different credential. Ending SSO session.");
                this.centralAuthenticationService.destroyTicketGrantingTicket(ticketGrantingTicketId);
            } catch (final AbstractTicketException e) {
                return newEvent(AbstractCasWebflowConfigurer.TRANSITION_ID_ERROR, e);
            }
            return newEvent(AbstractCasWebflowConfigurer.TRANSITION_ID_ERROR);

        }
        /**
         * Create ticket granting ticket for the given credentials.
         * Adds all warnings into the message context.
         *
         * @param context the context
         * @param credential the credential
         * @param messageContext the message context
         * @return the resulting event.
         * @since 4.1.0
         */
        protected Event createTicketGrantingTicket(final RequestContext context, final Credential credential,
                                                   final MessageContext messageContext) {
            try {
                final Service service = WebUtils.getService(context);
                final AuthenticationContextBuilder builder = new DefaultAuthenticationContextBuilder(
                        this.authenticationSystemSupport.getPrincipalElectionStrategy());
                final AuthenticationTransaction transaction =
                        AuthenticationTransaction.wrap(credential);
                this.authenticationSystemSupport.getAuthenticationTransactionManager().handle(transaction,  builder);
                final AuthenticationContext authenticationContext = builder.build(service);

                final TicketGrantingTicket tgt = this.centralAuthenticationService.createTicketGrantingTicket(authenticationContext);
                WebUtils.putTicketGrantingTicketInScopes(context, tgt);
                WebUtils.putWarnCookieIfRequestParameterPresent(this.warnCookieGenerator, context);
                putPublicWorkstationToFlowIfRequestParameterPresent(context);
                if (addWarningMessagesToMessageContextIfNeeded(tgt, messageContext)) {
                    return newEvent(SUCCESS_WITH_WARNINGS);
                }
                return newEvent(AbstractCasWebflowConfigurer.TRANSITION_ID_SUCCESS);

            } catch (final AuthenticationException e) {
                logger.debug(e.getMessage(), e);
                return newEvent(AUTHENTICATION_FAILURE, e);
            } catch (final Exception e) {
                logger.debug(e.getMessage(), e);
                return newEvent(AbstractCasWebflowConfigurer.TRANSITION_ID_ERROR, e);
            }
        }

        /**
         * Add warning messages to message context if needed.
         *
         * @param tgtId the tgt id
         * @param messageContext the message context
         * @return true if warnings were found and added, false otherwise.
         * @since 4.1.0
         */
        protected boolean addWarningMessagesToMessageContextIfNeeded(final TicketGrantingTicket tgtId, final MessageContext messageContext) {
            boolean foundAndAddedWarnings = false;
            for (final Map.Entry<String, HandlerResult> entry : tgtId.getAuthentication().getSuccesses().entrySet()) {
                for (final MessageDescriptor message : entry.getValue().getWarnings()) {
                    addWarningToContext(messageContext, message);
                    foundAndAddedWarnings = true;
                }
            }
            return foundAndAddedWarnings;

        }


        /**
         * Put public workstation into the flow if request parameter present.
         *
         * @param context the context
         */
        private static void putPublicWorkstationToFlowIfRequestParameterPresent(final RequestContext context) {
            if (StringUtils.isNotBlank(context.getExternalContext()
                    .getRequestParameterMap().get(PUBLIC_WORKSTATION_ATTRIBUTE))) {
                context.getFlowScope().put(PUBLIC_WORKSTATION_ATTRIBUTE, Boolean.TRUE);
            }
        }

        /**
         * New event based on the given id.
         *
         * @param id the id
         * @return the event
         */
        private Event newEvent(final String id) {
            return new Event(this, id);
        }

        /**
         * New event based on the id, which contains an error attribute referring to the exception occurred.
         *
         * @param id the id
         * @param error the error
         * @return the event
         */
        private Event newEvent(final String id, final Exception error) {
            return new Event(this, id, new LocalAttributeMap("error", error));
        }

        /**
         * Adds a warning message to the message context.
         *
         * @param context Message context.
         * @param warning Warning message.
         */
        private static void addWarningToContext(final MessageContext context, final MessageDescriptor warning) {
            final MessageBuilder builder = new MessageBuilder()
                    .warning()
                    .code(warning.getCode())
                    .defaultText(warning.getDefaultMessage())
                    .args(warning.getParams());
            context.addMessage(builder.build());
        }

        public void setCentralAuthenticationService(final CentralAuthenticationService centralAuthenticationService) {
            this.centralAuthenticationService = centralAuthenticationService;
        }

        public void setWarnCookieGenerator(final CookieGenerator warnCookieGenerator) {
            this.warnCookieGenerator = warnCookieGenerator;
        }

        public void setAuthenticationSystemSupport(final AuthenticationSystemSupport authenticationSystemSupport) {
            this.authenticationSystemSupport = authenticationSystemSupport;
        }
        
        
        public final String validatorCode(final RequestContext context,
                final Credential credentials, final MessageContext messageContext)
                throws Exception {
            final HttpServletRequest request = WebUtils
                    .getHttpServletRequest(context);
            HttpSession session = request.getSession();
            //生成的验证码
            String authcode = (String) session
                    .getAttribute(com.google.code.kaptcha.Constants.KAPTCHA_SESSION_KEY);
            session.removeAttribute(com.google.code.kaptcha.Constants.KAPTCHA_SESSION_KEY);

            UsernamePasswordCredentialWithAuthCode upc = (UsernamePasswordCredentialWithAuthCode) credentials;
            //用户 输入的验证码
            String submitAuthcode = upc.getAuthcode();
            if (StringUtils.isEmpty(submitAuthcode)
                    || StringUtils.isEmpty(authcode)) {
                populateErrorsInstance(new NullAuthcodeAuthenticationException(),
                        messageContext);
                return "error";
            }
            if (submitAuthcode.equalsIgnoreCase(authcode)) {
                return "success";
            }
            populateErrorsInstance(new BadAuthcodeAuthenticationException(),
                    messageContext);
            return "error";
        }

        private void populateErrorsInstance(final RootCasException e,
                final MessageContext messageContext) {

            try {
                messageContext.addMessage(new MessageBuilder().error()
                        .code(e.getCode()).defaultText(e.getCode()).build());
            } catch (final Exception fe) {
                logger.error(fe.getMessage(), fe);
            }
        }
        
        
    }

    4.定义异常类NullAuthcodeAuthenticationException和BadAuthcodeAuthenticationException:


    package org.jasig.cas.web.flow;

    import org.jasig.cas.authentication.RootCasException;

    public class NullAuthcodeAuthenticationException extends RootCasException {

        /** Serializable ID for unique id. */
        private static final long serialVersionUID = 5501212207531289993L;

        /** Code description. */
        public static final String CODE = "required.authcode";

        /**
         * Constructs a TicketCreationException with the default exception code.
         */
        public NullAuthcodeAuthenticationException() {
            super(CODE);
        }

        /**
         * Constructs a TicketCreationException with the default exception code and
         * the original exception that was thrown.
         * 
         * @param throwable
         *            the chained exception
         */
        public NullAuthcodeAuthenticationException(final Throwable throwable) {
            super(CODE, throwable);
        }
    }

    ----------------------------------------------------------------------------------------------------------------------------------

    package org.jasig.cas.web.flow;

    import org.jasig.cas.authentication.RootCasException;

    public class BadAuthcodeAuthenticationException extends RootCasException {

        /** Serializable ID for unique id. */
        private static final long serialVersionUID = 5501212207531289993L;

        /** Code description. */
        public static final String CODE = "error.authentication.authcode.bad";

        /**
         * Constructs a TicketCreationException with the default exception code.
         */
        public BadAuthcodeAuthenticationException() {
            super(CODE);
        }

        /**
         * Constructs a TicketCreationException with the default exception code and
         * the original exception that was thrown.
         * 
         * @param throwable
         *            the chained exception
         */
        public BadAuthcodeAuthenticationException(final Throwable throwable) {
            super(CODE, throwable);
        }
    }

    5、在login_webflow.xml修改登录验证流程:

    修改UsernamePasswordCredentialWithAuthCode你自己定义的路劲

    验证码校验:

    <transition on="submit" bind="true" validate="true"
                to="validatorCode" />
            <!-- <transition on="submit" bind="true" validate="true" to="realSubmit" 
                /> -->
        </view-state>

        <!-- 新添加的校验验证码 -->

    <action-state id="validatorCode">
    <evaluate
    expression="authenticationViaFormAction.validatorCode(flowRequestContext, flowScope.credential, messageContext)" />
    <transition on="error" to="generateLoginTicket"/>
    <transition on="success" to="realSubmit" />
    </action-state>

    6、messages_zh_CN.properties增加国际化显示信息:

    screen.welcome.label.authcode=u9A8Cu8BC1u7801:

    screen.welcome.label.authcode.accesskey=a

    required.authcode=u5FC5u987Bu5F55u5165u9A8Cu8BC1u7801u3002

    error.authentication.authcode.bad=u9A8Cu8BC1u7801u8F93u5165u6709u8BEFu3002

    7.登录页面casLoginView.jsp添加验证码输入框:

            <!-- 验证码 -->
                <spring:message code="screen.welcome.label.authcode" />
                <img onclick="this.src='captcha.jpg?'+Math.random()" width="93"
                    height="30" src="captcha.jpg">
              
                <div class="login-ic">
                    <i class="icys"></i>
                    <form:input cssClass="required" cssErrorClass="error" id="authcode"
                        size="10" tabindex="2" path="authcode"
                        accesskey="${authcodeAccessKey}" htmlEscape="true"
                        autocomplete="off" />
                    <div class="clear"></div>

                </div>


              

    8、如果要默认中文页面显示,修改cas-servlet.xml 下的local Resolver默认值为zh_CN:

     <bean id="localeResolver" class="org.springframework.web.servlet.i18n.CookieLocaleResolver" p:defaultLocale="zh_CN" />

        

  • 相关阅读:
    expect详解及自动登录脚本的实现
    NFS服务端+客户端配置
    交互式shell脚本对话框----whiptail指令
    自定制Centos7.3系统镜像(ISO)
    云原生简述
    Linux下修改MTU(最大传输单元)
    MySQL-5.7组提交(Group Commit)原理
    AWS putty终端ssh密钥登陆方法
    一个简单的从web页面获取数据插入数据库的小程序
    新建一个简单的Java web前后台交互小程序时报错:java.lang.ClassNotFoundException: com.microsoft.sqlserver.jdbc.SqlServerDriver
  • 原文地址:https://www.cnblogs.com/lvgg/p/6993239.html
Copyright © 2011-2022 走看看