cas5.3.9自定义手机短信验证码登录

cas自定义多种登录方式

cas添加手机短信验证码登录

全部基于SpringBoot,以及SpringWebflow开发,请在有此基础再进行学习!

添加Maven依赖

<dependency>
            <groupId>org.apereo.cas</groupId>
            <artifactId>cas-server-core-authentication-api</artifactId>
        </dependency>

        <dependency>
            <groupId>org.apereo.cas</groupId>
            <artifactId>cas-server-core-webflow</artifactId>
            <version>${cas.version}</version>
        </dependency>

        <dependency>
            <groupId>org.apereo.cas</groupId>
            <artifactId>cas-server-core-webflow-api</artifactId>
             <version>${cas.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apereo.cas</groupId>
            <artifactId>cas-server-core-web-api</artifactId>
             <version>${cas.version}</version>
        </dependency>
        <dependency>
             <groupId>javax.servlet</groupId>
             <artifactId>javax.servlet-api</artifactId>
             <version>3.1.0</version>
             <scope>provided</scope>
        </dependency>

扩展caswebflow默认的登录方式

import net.pubone.cas.support.mobile.credential.MobileIdCredential;
import org.apereo.cas.configuration.CasConfigurationProperties;
import org.apereo.cas.web.flow.CasWebflowConstants;
import org.apereo.cas.web.flow.configurer.AbstractCasWebflowConfigurer;
import org.springframework.context.ApplicationContext;
import org.springframework.webflow.definition.registry.FlowDefinitionRegistry;
import org.springframework.webflow.engine.ActionState;
import org.springframework.webflow.engine.Flow;
import org.springframework.webflow.engine.ViewState;
import org.springframework.webflow.engine.builder.support.FlowBuilderServices;

public class MobileidWebflowConfigurer extends AbstractCasWebflowConfigurer {
    public MobileidWebflowConfigurer(FlowBuilderServices flowBuilderServices, FlowDefinitionRegistry loginFlowDefinitionRegistry, ApplicationContext applicationContext, CasConfigurationProperties casProperties) {
        super(flowBuilderServices, loginFlowDefinitionRegistry, applicationContext, casProperties);

    }
    private static final String EVENT_ID_START_AUTHENTICATE_MOBILE_ID = "startAuthenticateMobileId";
    @Override
    protected void doInitialize() {

        final Flow flow = getLoginFlow();
        if (flow != null) {
            //创建Action
            final ActionState actionState = createActionState(flow, EVENT_ID_START_AUTHENTICATE_MOBILE_ID,
            		//自定义Action
                    createEvaluateAction("mobileidCredentialsAction"));
            //添加成功后的Transition
            actionState.getTransitionSet().add(createTransition(CasWebflowConstants.TRANSITION_ID_SUCCESS,
                    CasWebflowConstants.STATE_ID_CREATE_TICKET_GRANTING_TICKET));
            //添加警告的Transition
            actionState.getTransitionSet()
                    .add(createTransition(CasWebflowConstants.TRANSITION_ID_WARN, CasWebflowConstants.TRANSITION_ID_WARN));
            //添加错误的Transition跳转到login
            actionState.getTransitionSet()
                    .add(createTransition(CasWebflowConstants.TRANSITION_ID_ERROR, CasWebflowConstants.STATE_ID_VIEW_LOGIN_FORM));
            //添加认证错误的的Transition跳转到login并显示错误信息
            actionState.getTransitionSet().add(createTransition(CasWebflowConstants.TRANSITION_ID_AUTHENTICATION_FAILURE,
                    CasWebflowConstants.STATE_ID_HANDLE_AUTHN_FAILURE));

            actionState.getExitActionList().add(createEvaluateAction("clearWebflowCredentialsAction"));
            registerMultifactorProvidersStateTransitionsIntoWebflow(actionState);
            ViewState viewLoginState = (ViewState) flow.getState(CasWebflowConstants.STATE_ID_VIEW_LOGIN_FORM);

         
  			createTransitionForState(viewLoginState, "submitMobileId", EVENT_ID_START_AUTHENTICATE_MOBILE_ID, true);
        }
    }
}

自定义的手机短信登录的Action
这里使用了lombok 所以idea要装一个lombok插件(自行百度)

package net.pubone.cas.support.mobile.action;
import lombok.extern.slf4j.Slf4j;
import net.pubone.cas.support.mobile.credential.MobileIdCredential;

import org.apereo.cas.authentication.Credential;
import org.apereo.cas.authentication.adaptive.AdaptiveAuthenticationPolicy;
import org.apereo.cas.web.flow.actions.AbstractNonInteractiveCredentialsAction;
import org.apereo.cas.web.flow.resolver.CasDelegatingWebflowEventResolver;
import org.apereo.cas.web.flow.resolver.CasWebflowEventResolver;
import org.apereo.cas.web.support.WebUtils;

import org.springframework.webflow.execution.RequestContext;
import static org.apereo.cas.CipherExecutor.LOGGER;
import javax.servlet.http.HttpServletRequest;


@Slf4j
public class MobileIdCredentialsAction extends AbstractNonInteractiveCredentialsAction {
    public MobileIdCredentialsAction(CasDelegatingWebflowEventResolver initialAuthenticationAttemptWebflowEventResolver,
                                     CasWebflowEventResolver serviceTicketRequestWebflowEventResolver,
                                     AdaptiveAuthenticationPolicy adaptiveAuthenticationPolicy) {
        super(initialAuthenticationAttemptWebflowEventResolver, serviceTicketRequestWebflowEventResolver,
                adaptiveAuthenticationPolicy);
    }

    @Override
    protected Credential constructCredentialsFromRequest(RequestContext requestContext) {
        try {
            final HttpServletRequest request;
            request = WebUtils.getHttpServletRequestFromExternalWebflowContext(requestContext);
            MobileIdCredential credentials = new MobileIdCredential(request.getParameter("phoneNumber"), "");
            if (credentials != null) {
                LOGGER.debug("Received mobile authentication request from credentials [{}]", credentials);
                return credentials;
            }
        } catch (final Exception e) {
            LOGGER.warn(e.getMessage(), e);
            e.printStackTrace();
        }
        return null;
    }

}

自定义credential

package net.pubone.cas.support.mobile.credential;
import lombok.*;
import org.apereo.cas.authentication.AbstractCredential;
import org.apereo.cas.authentication.OneTimeTokenCredential;
@ToString
@Setter
@Getter
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(callSuper = true)
public class MobileIdCredential extends AbstractCredential {

    private static final long serialVersionUID = 1L;
    private String phoneNumber;
    private String validataCode;
    @Override
    public String getId() {
        return this.phoneNumber;
    }
    
}

自定义Handler

package net.pubone.cas.support.mobile.handler;
import lombok.extern.slf4j.Slf4j;
import net.pubone.cas.entity.Puser;
import net.pubone.cas.execption.NoFindUserExecption;
import net.pubone.cas.repository.UserRepository;
import net.pubone.cas.support.mobile.credential.MobileIdCredential;
import org.apereo.cas.authentication.AuthenticationHandlerExecutionResult;
import org.apereo.cas.authentication.Credential;
import org.apereo.cas.authentication.PreventedException;
import org.apereo.cas.authentication.handler.support.AbstractPreAndPostProcessingAuthenticationHandler;
import org.apereo.cas.authentication.principal.Principal;
import org.apereo.cas.authentication.principal.PrincipalFactory;
import org.apereo.cas.services.ServicesManager;
import org.springframework.beans.factory.annotation.Autowired;
import javax.security.auth.login.FailedLoginException;
import java.security.GeneralSecurityException;
import java.util.Objects;

import static org.apereo.cas.CipherExecutor.LOGGER;

@Slf4j
public class MobileHandler extends AbstractPreAndPostProcessingAuthenticationHandler {

    public MobileHandler(String name, ServicesManager servicesManager, PrincipalFactory principalFactory, Integer order ) {
        super(name, servicesManager, principalFactory, order);

    }
    //@Autowired
    //UserRepository jpaMobileUserRepository;

    @Override
    public boolean supports(Credential credential) {
        //判断传递过来的Credential 是否是自己能处理的类型
        return credential instanceof MobileIdCredential;
    }
    @Override
    protected AuthenticationHandlerExecutionResult doAuthentication(Credential credential) throws GeneralSecurityException, PreventedException {
        MobileIdCredential mobileIdCredential = (MobileIdCredential) credential;



        String phoneNumber = mobileIdCredential.getPhoneNumber();
        String validataCode = mobileIdCredential.getValidataCode();
        System.out.println(phoneNumber);
        System.out.println(validataCode);
        Puser puser = null;
      if(phoneNumber==null){
          log.debug("手机号码为null");
         throw new FailedLoginException("手机号码必须填写");
      }
      //TODO 这里做手机验证码校验操作
	throw new FailedLoginException("手机号码必须填写");
        Principal principal = principalFactory.createPrincipal(credential.getId());
        return  createHandlerResult(credential,
                principal);

    }
}

配置上面我们自定义的Action,webflow,credential,handler

package net.pubone.cas.support.mobile.config;
import net.pubone.cas.support.mobile.action.MobileIdCredentialsAction;
import net.pubone.cas.support.mobile.handler.MobileHandler;
import net.pubone.cas.support.mobile.webflow.MobileidWebflowConfigurer;
import org.apereo.cas.authentication.AuthenticationEventExecutionPlan;
import org.apereo.cas.authentication.AuthenticationEventExecutionPlanConfigurer;
import org.apereo.cas.authentication.AuthenticationHandler;
import org.apereo.cas.authentication.adaptive.AdaptiveAuthenticationPolicy;
import org.apereo.cas.authentication.principal.DefaultPrincipalFactory;
import org.apereo.cas.configuration.CasConfigurationProperties;
import org.apereo.cas.services.ServicesManager;
import org.apereo.cas.ticket.registry.TicketRegistry;
import org.apereo.cas.web.flow.CasWebflowConfigurer;
import org.apereo.cas.web.flow.CasWebflowExecutionPlan;
import org.apereo.cas.web.flow.CasWebflowExecutionPlanConfigurer;
import org.apereo.cas.web.flow.config.CasWebflowContextConfiguration;
import org.apereo.cas.web.flow.resolver.CasDelegatingWebflowEventResolver;
import org.apereo.cas.web.flow.resolver.CasWebflowEventResolver;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;

import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.webflow.definition.registry.FlowDefinitionRegistry;
import org.springframework.webflow.engine.builder.support.FlowBuilderServices;
import org.springframework.webflow.execution.Action;



@Configuration("mobileLoginConfiguration")
@AutoConfigureBefore(value = CasWebflowContextConfiguration.class)
@EnableConfigurationProperties(CasConfigurationProperties.class)
public class MobileidConfiguration implements CasWebflowExecutionPlanConfigurer {

    @Autowired
    private CasConfigurationProperties casProperties;

    @Autowired
    @Qualifier("logoutFlowRegistry")
    private FlowDefinitionRegistry logoutFlowRegitry;

    @Autowired
    @Qualifier("loginFlowRegistry")
    private FlowDefinitionRegistry loginFlowRegistry;

    @Autowired
    private ApplicationContext applicationContext;

    @Autowired
    @Qualifier("builder")
    private FlowBuilderServices builder;

    @Autowired
    @Qualifier("adaptiveAuthenticationPolicy")
    private AdaptiveAuthenticationPolicy adaptiveAuthenticationPolicy;

    @Autowired
    @Qualifier("serviceTicketRequestWebflowEventResolver")
    private CasWebflowEventResolver serviceTicketRequestWebflowEventResolver;

    @Autowired
    @Qualifier("initialAuthenticationAttemptWebflowEventResolver")
    private CasDelegatingWebflowEventResolver initialAuthenticationAttemptWebflowEventResolver;

    @ConditionalOnMissingBean(name = "mobileidWebflowConfigurer")
    @Bean
    public CasWebflowConfigurer mobileidWebflowConfigurer() {
        MobileidWebflowConfigurer configurer = new MobileidWebflowConfigurer(builder,
                loginFlowRegistry, applicationContext, casProperties);
       // configurer.setLogoutFlowDefinitionRegistry(logoutFlowRegitry);
        return configurer;
    }

    @Bean
    public Action mobileidCredentialsAction() {
        return new MobileIdCredentialsAction(initialAuthenticationAttemptWebflowEventResolver,
                serviceTicketRequestWebflowEventResolver, adaptiveAuthenticationPolicy);
    }


    @Configuration("mobileidAuthenticationEventExecutionPlanConfiguration")
    public class MobileidAuthenticationEventExecutionPlanConfiguration
            implements AuthenticationEventExecutionPlanConfigurer {
        @Autowired
        @Qualifier("servicesManager")
        private ServicesManager servicesManager;
        //注册验证器
        @DependsOn("mobileUserRepository")
        @Bean
        public AuthenticationHandler mobileAuthenticationHandler() {
            //优先验证
            return new MobileHandler("mobileHandler",
                    servicesManager, new DefaultPrincipalFactory(), 1);
        }

        @Override
        public void configureAuthenticationExecutionPlan(final AuthenticationEventExecutionPlan plan) {
            plan.registerAuthenticationHandler(mobileAuthenticationHandler());
        }

    }
    @Override
    public void configureWebflowExecutionPlan(final CasWebflowExecutionPlan plan) {
        plan.registerWebflowConfigurer(mobileidWebflowConfigurer());
    }
}

最后
在 resources/META-INF/spring.factories中配置让SpringBoot扫描到我们的配置类

org.springframework.boot.autoconfigure.EnableAutoConfiguration=net.pubone.cas.support.mobile.config.MobileidConfiguration

在 resources/templates/casLoginView.html中加入一段html

<form>
<input type="hidden" name="execution" th:value="${flowExecutionKey}" />
<input type="hidden" name="_eventId" value="submitMobileId" />
<input  placeholder="手机号" name="phoneNumber" autocomplete="off"/>
<input  placeholder="验证码" name="validataCode" autocomplete="off"/>
 <input class="button" id="login-submit" style="color:#fff;"
                           th:value="#{screen.welcome.button.login}"
                           tabindex="6"
     						type="submit"
                    />
</form>

效果如下
在这里插入图片描述
进行手机验证码登录时cas会调用我们自己的Action 里的 constructCredentialsFromRequest方法
在这里插入图片描述
创建好Credential后会进入我们自定义的Handler
在这里插入图片描述
如果在doAuthentication方法中抛出异常则认证失败
在这里插入图片描述
登录成功在这里插入图片描述

  • 4
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 44
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 44
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值