Cas5.3.2之自定义登入流程(实现验证码)

自定义验证很重要,因为我们后续的很多功能,都是基于自定义验证。 
CAS服务器的org.apereo.cas.authentication.AuthenticationManager负责基于提供的凭证信息进行用户认证。与Spring Security很相似,实际的认证委托给了一个或多个实现了org.apereo.cas.authentication.AuthenticationHandler接口的处理类。在cas的认证过程中逐个执行authenticationHandlers中配置的认证管理,直到有一个成功为止。 
CAS内置了一些AuthenticationHandler实现类,如下图所示,QueryDatabaseAuthenticationHandler中提供了基于jdbc的用户认
Cas5.3.2之自定义登入流程(实现验证码)_第1张图片

如果需要实现自定义登录,只需要实现org.apereo.cas.authentication.AuthenticationHandler接口即可。当然也可以利用已有的实现,比如创建一个继承自org.apereo.cas.authentication.handler.support.AbstractPreAndPostProcessingAuthenticationHandler的类。下面我们就来实现自定义验证。

自定义登入

pom.xml 添加如下依赖jar包


				
					org.apereo.cas
					cas-server-core-webflow
					${cas.version}
				
				
				
					org.apereo.cas
					cas-server-core-authentication
					${cas.version}
				
				
					org.apereo.cas
					cas-server-core-authentication-api
					${cas.version}
				
				
					org.apereo.cas
					cas-server-core-webflow-api
					${cas.version}
				

自定义验证类,继承AbstractPreAndPostProcessingAuthenticationHandler

package com.digipower.authentication.handler;

import java.security.GeneralSecurityException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.security.auth.login.AccountNotFoundException;
import javax.security.auth.login.FailedLoginException;
import org.apache.commons.lang.StringUtils;
import org.apereo.cas.authentication.AuthenticationHandlerExecutionResult;
import org.apereo.cas.authentication.Credential;
import org.apereo.cas.authentication.MessageDescriptor;
import org.apereo.cas.authentication.PreventedException;
import org.apereo.cas.authentication.handler.support.AbstractPreAndPostProcessingAuthenticationHandler;
import org.apereo.cas.authentication.principal.PrincipalFactory;
import org.apereo.cas.services.ServicesManager;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import com.digipower.encrypt.PasswordEncryption;
import com.digipower.exception.CaptchaException;
import com.digipower.verification.code.UsernamePasswordCaptchaCredential;
/**
 * 自定义用户认证核心代码
 * @author zzg
 *
 */
public class UsernamePasswordCaptchaAuthenticationHandler extends AbstractPreAndPostProcessingAuthenticationHandler {

	public UsernamePasswordCaptchaAuthenticationHandler(String name, ServicesManager servicesManager,
			PrincipalFactory principalFactory, Integer order) {
		super(name, servicesManager, principalFactory, order);
		// TODO Auto-generated constructor stub
	}

	@Override
	protected AuthenticationHandlerExecutionResult doAuthentication(Credential credential)
			throws GeneralSecurityException, PreventedException {
		// TODO Auto-generated method stub
		// 用户凭证
		UsernamePasswordCaptchaCredential myCredential = (UsernamePasswordCaptchaCredential) credential;
		String requestCaptcha = myCredential.getCaptcha();
		ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
		Object attribute = attributes.getRequest().getSession().getAttribute("captcha");

		String realCaptcha = attribute == null ? null : attribute.toString();

		if (StringUtils.isBlank(requestCaptcha) || !requestCaptcha.equalsIgnoreCase(realCaptcha)) {
			throw new CaptchaException("验证码错误");
		}

		// 验证用户名和密码
		DriverManagerDataSource d = new DriverManagerDataSource();
		d.setDriverClassName("com.mysql.jdbc.Driver");
		d.setUrl(
				"jdbc:mysql://192.168.1.73:3306/boot-security?serverTimezone=UTC&useSSL=false&allowPublicKeyRetrieval=true");
		d.setUsername("root");
		d.setPassword("digipower");

		JdbcTemplate template = new JdbcTemplate();
		template.setDataSource(d);

		// 查询数据库加密的的密码
		Map user = template.queryForMap("select pswd from u_user where nickname = ?",
				myCredential.getUsername());

		if (user == null) {
			throw new AccountNotFoundException("用户名输入错误或用户名不存在");
		}

		// 返回多属性
		Map map = new HashMap<>();
		map.put("username", myCredential.getUsername());

		// 密码加密验证(MD5 32位 大写)
		PasswordEncryption passwordEncryption = new PasswordEncryption();
		List  warning = new ArrayList();
		if (passwordEncryption.matches(myCredential.getPassword(), user.get("pswd").toString())) {
			return createHandlerResult(myCredential, principalFactory.createPrincipal(myCredential.getUsername(), map),
					warning);
		}

		throw new FailedLoginException("密码输入错误");
	}

	// 判断是否支持自定义用户登入凭证
	@Override
	public boolean supports(Credential credential) {
		// TODO Auto-generated method stub
		return credential instanceof UsernamePasswordCaptchaCredential;
	}

}

绑定自定义认证流程和自定义凭证信息

package com.digipower.captcha.config;

import org.apereo.cas.authentication.AuthenticationEventExecutionPlan;
import org.apereo.cas.authentication.AuthenticationEventExecutionPlanConfigurer;
import org.apereo.cas.authentication.AuthenticationHandler;
import org.apereo.cas.authentication.principal.DefaultPrincipalFactory;
import org.apereo.cas.configuration.CasConfigurationProperties;
import org.apereo.cas.services.ServicesManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.digipower.authentication.handler.UsernamePasswordCaptchaAuthenticationHandler;

/**
 * 自定义用户登入流程使用的自定义的用户凭证
 * @author zzg
 *
 */

@Configuration("usernamePasswordCaptchaConfig")
@EnableConfigurationProperties(CasConfigurationProperties.class)
public class UsernamePasswordCaptchaConfig implements AuthenticationEventExecutionPlanConfigurer{

	@Autowired
    private CasConfigurationProperties casProperties;

    @Autowired
    @Qualifier("servicesManager")
    private ServicesManager servicesManager;
    
	 /**
     * 用户定义用户登入处理器
     * @return
     */
    @Bean
    public AuthenticationHandler rememberMeUsernamePasswordCaptchaAuthenticationHandler() {
    	UsernamePasswordCaptchaAuthenticationHandler handler = new UsernamePasswordCaptchaAuthenticationHandler(
    			UsernamePasswordCaptchaAuthenticationHandler.class.getSimpleName(),
                servicesManager,
                new DefaultPrincipalFactory(),
                9);
        return handler;
    }

	/**
	 * 
	 * 

Title: configureAuthenticationExecutionPlan

*

Description: 用户自定义表单处理注册

* @param plan * @see org.apereo.cas.authentication.AuthenticationEventExecutionPlanConfigurer#configureAuthenticationExecutionPlan(org.apereo.cas.authentication.AuthenticationEventExecutionPlan) */ @Override public void configureAuthenticationExecutionPlan(AuthenticationEventExecutionPlan plan) { // TODO Auto-generated method stub plan.registerAuthenticationHandler(rememberMeUsernamePasswordCaptchaAuthenticationHandler()); } }

创建用户登入凭证,添加验证码属性

package com.digipower.verification.code;

import org.apache.commons.lang.builder.HashCodeBuilder;
import org.apereo.cas.authentication.RememberMeUsernamePasswordCredential;

/**
 * 自定义用户凭证,添加验证码属性
 * @author zzg
 *
 */
@SuppressWarnings("serial")
public class UsernamePasswordCaptchaCredential extends RememberMeUsernamePasswordCredential  {

	private String captcha;

    public String getCaptcha() {
        return captcha;
    }

    public void setCaptcha(String captcha) {
        this.captcha = captcha;
    }

    @Override
    public int hashCode() {
        return new HashCodeBuilder()
                .appendSuper(super.hashCode())
                .append(this.captcha)
                .toHashCode();
    }


}

重新定义Apereo Cas5 服务端的登入流程

package com.digipower.webflow.action;

import org.apereo.cas.configuration.CasConfigurationProperties;
import org.apereo.cas.web.flow.CasWebflowConstants;
import org.apereo.cas.web.flow.configurer.DefaultLoginWebflowConfigurer;
import org.springframework.context.ApplicationContext;
import org.springframework.webflow.definition.registry.FlowDefinitionRegistry;
import org.springframework.webflow.engine.Flow;
import org.springframework.webflow.engine.ViewState;
import org.springframework.webflow.engine.builder.BinderConfiguration;
import org.springframework.webflow.engine.builder.support.FlowBuilderServices;

import com.digipower.verification.code.UsernamePasswordCaptchaCredential;

/**
 * 自定义系统登入设置自定义用户凭证
 * @author zzg
 *
 */
public class CaptchaWebflowConfigurer extends DefaultLoginWebflowConfigurer {


	
	public CaptchaWebflowConfigurer(FlowBuilderServices flowBuilderServices,
			FlowDefinitionRegistry flowDefinitionRegistry, ApplicationContext applicationContext,
			CasConfigurationProperties casProperties) {
		super(flowBuilderServices, flowDefinitionRegistry, applicationContext, casProperties);
	}

	@Override
	protected void createRememberMeAuthnWebflowConfig(Flow flow) {
		 if (casProperties.getTicket().getTgt().getRememberMe().isEnabled()) {
	            createFlowVariable(flow, CasWebflowConstants.VAR_ID_CREDENTIAL, UsernamePasswordCaptchaCredential.class);
	            final ViewState state = getState(flow, CasWebflowConstants.STATE_ID_VIEW_LOGIN_FORM, ViewState.class);
	            final BinderConfiguration cfg = getViewStateBinderConfiguration(state);
	            cfg.addBinding(new BinderConfiguration.Binding("rememberMe", null, false));
	            cfg.addBinding(new BinderConfiguration.Binding("captcha", null, true));
	        } else {
	            createFlowVariable(flow, CasWebflowConstants.VAR_ID_CREDENTIAL, UsernamePasswordCaptchaCredential.class);
	            final ViewState state = getState(flow, CasWebflowConstants.STATE_ID_VIEW_LOGIN_FORM, ViewState.class);
	            final BinderConfiguration cfg = getViewStateBinderConfiguration(state);
	            // cfg.addBinding(new BinderConfiguration.Binding("rememberMe", null, false));
	            cfg.addBinding(new BinderConfiguration.Binding("captcha", null, true));
	        }
	}

}

修改Apereo Cas 5 系统自带的登入流程定义webflow

在login-webflow.xml/viewLoginForm 添加如下代码:

	

源码修改如下:




    
        
        
    

    
        
            
            
          	
        
        
    

    
        
        
        
        
        
        
    


将自定义登入流程添加如Apereo Cas 5服务器中webflow 中

package com.digipower.captcha.config;

import org.apereo.cas.configuration.CasConfigurationProperties;
import org.apereo.cas.web.flow.CasWebflowConfigurer;
import org.apereo.cas.web.flow.config.CasWebflowContextConfiguration;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
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.webflow.definition.registry.FlowDefinitionRegistry;
import org.springframework.webflow.engine.builder.support.FlowBuilderServices;
import com.digipower.webflow.action.CaptchaWebflowConfigurer;

/**
 * 自定义登入流程配置入webflow
 * @author zzg
 *
 */

@Configuration("captchaWebflowConfigurer")
@EnableConfigurationProperties(CasConfigurationProperties.class)
@AutoConfigureBefore(value = CasWebflowContextConfiguration.class)
public class CaptchaConfigurer {
	@Autowired
	@Qualifier("loginFlowRegistry")
	private FlowDefinitionRegistry loginFlowRegistry;
	@Autowired
	private ApplicationContext applicationContext;
	@Autowired
	private CasConfigurationProperties casProperties;
	@Autowired
	private FlowBuilderServices flowBuilderServices;

	@Bean("defaultLoginWebflowConfigurer")
	public CasWebflowConfigurer defaultLoginWebflowConfigurer() {
		CasWebflowConfigurer c = new CaptchaWebflowConfigurer(flowBuilderServices, loginFlowRegistry,
				applicationContext, casProperties);
		c.initialize();
		return c;
	}
}

补充相关的工具类:Kaptcha 图形验证码初始化,用户密码加密工具类,springBean 工具类和相关自定义异常

package com.digipower.kaptcha.config;

import javax.servlet.ServletException;

import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.google.code.kaptcha.servlet.KaptchaServlet;

@Configuration
public class KaptchaConfig {
	@Bean
    public ServletRegistrationBean servletRegistrationBean() throws ServletException {
        ServletRegistrationBean servlet = new ServletRegistrationBean(new KaptchaServlet(),  "/kaptcha.jpg");//加载路径
        servlet.addInitParameter("kaptcha.border", "no"/* kborder */);// 无边框
        servlet.addInitParameter("kaptcha.session.key", "captcha");// session key
        servlet.addInitParameter("kaptcha.textproducer.font.color", "black");
        servlet.addInitParameter("kaptcha.textproducer.font.size", "25");
        servlet.addInitParameter("kaptcha.obscurificator.impl", "com.google.code.kaptcha.impl.WaterRipple");
        servlet.addInitParameter("kaptcha.noise.impl", "com.google.code.kaptcha.impl.NoNoise");
        servlet.addInitParameter("kaptcha.image.width", "90");
        servlet.addInitParameter("kaptcha.image.height", "33");
        servlet.addInitParameter("kaptcha.textproducer.char.length", "4");
        servlet.addInitParameter("kaptcha.textproducer.char.space", "5");
        servlet.addInitParameter("kaptcha.background.clear.from", "247,247,247"); // 和登录框背景颜色一致
        servlet.addInitParameter("kaptcha.background.clear.to", "247,247,247");
        return servlet;
    }
}
package com.digipower.encrypt;

import org.apache.commons.codec.digest.DigestUtils;
import org.apereo.cas.authentication.handler.support.AbstractPreAndPostProcessingAuthenticationHandler;
import org.springframework.security.crypto.password.PasswordEncoder;

/**
 * 自定义数据密码加密工具类
 * @author zzg
 *
 */
public class PasswordEncryption implements PasswordEncoder{

	@Override
	public String encode(CharSequence password) {
		return DigestUtils.md5Hex(password.toString()).toUpperCase();
	}

	@Override
	public boolean matches(CharSequence rawPassword, String encodePassword) {
		// 判断密码是否存在
        if (rawPassword == null) {
            return false;
        }
        //通过md5加密后的密码
        String pass = this.encode(rawPassword.toString());
        //比较密码是否相等的问题
        return pass.equals(encodePassword);
	}
	
	AbstractPreAndPostProcessingAuthenticationHandler  handler;

}
package com.digipower.exception;

import javax.security.auth.login.AccountException;

@SuppressWarnings("serial")
public class CaptchaException extends AccountException {
	public CaptchaException() {
		super();
		// TODO Auto-generated constructor stub
	}

	public CaptchaException(String msg) {
		super(msg);
		// TODO Auto-generated constructor stub
	}

}
package com.digipower.util;

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;


@Component
public class SpringContextUtils implements ApplicationContextAware {

	private static ApplicationContext applicationContext;

	@Override
	public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
		SpringContextUtils.applicationContext = applicationContext;
	}

	public static Object getBean(String name) {
		return applicationContext.getBean(name);
	}

	public static  T getBean(String name, Class requiredType) {
		return applicationContext.getBean(name, requiredType);
	}

	public static boolean containsBean(String name) {
		return applicationContext.containsBean(name);
	}

	public static boolean isSingleton(String name) {
		return applicationContext.isSingleton(name);
	}

	public static Class getType(String name) {
		return applicationContext.getType(name);
	}

}

加载该配置类

在resources\META-INF\spring.factories中配置该类

org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.digipower.captcha.config.CaptchaConfigurer,\
	com.digipower.kaptcha.config.KaptchaConfig,\
	com.digipower.captcha.config.UsernamePasswordCaptchaConfig,\
	com.digipower.util.SpringContextUtils

系统登入页面修改,添加验证码(/templates/fragments/loginfrom.html),添加如下代码:

 

apereo cas5 自定义项目的整体结构:

Cas5.3.2之自定义登入流程(实现验证码)_第2张图片

pom.xml 文件



	4.0.0
	org.apereo.cas
	cas-overlay
	war
	1.0

	
		
			
				com.rimerosolutions.maven.plugins
				wrapper-maven-plugin
				0.0.5
				
					true
					MD5
				
			
			
				org.springframework.boot
				spring-boot-maven-plugin
				${springboot.version}
				
					${mainClassName}
					true
					${isExecutable}
					WAR
				
				
					
						
							repackage
						
					
				
			
			
				org.apache.maven.plugins
				maven-war-plugin
				2.6
				
					cas
					false
					false
					
						false
						${manifestFileToUse}
					
					
						
							org.apereo.cas
							cas-server-webapp${app.server}
						
					
				
			
			
				org.apache.maven.plugins
				maven-compiler-plugin
				3.3
			
		
		cas
	

	
		8.0.13
		5.3.9
		1.5.18.RELEASE
		
		-tomcat

		org.springframework.boot.loader.WarLauncher
		false
		${project.build.directory}/war/work/org.apereo.cas/cas-server-webapp${app.server}/META-INF/MANIFEST.MF

		1.8
		1.8
		UTF-8
	

	
		
			sonatype-releases
			http://oss.sonatype.org/content/repositories/releases/
			
				false
			
			
				true
			
		
		
			sonatype-snapshots
			https://oss.sonatype.org/content/repositories/snapshots/
			
				true
			
			
				false
			
		
		
			shibboleth-releases
			https://build.shibboleth.net/nexus/content/repositories/releases
		
	

	
		
			
				true
			
			default
			
				
					org.apereo.cas
					cas-server-webapp${app.server}
					${cas.version}
					war
					runtime
				
				

				
				
					org.apereo.cas
					cas-server-support-jdbc
					${cas.version}
				
				
					org.apereo.cas
					cas-server-support-jdbc-drivers
					${cas.version}
				
				
				
					mysql
					mysql-connector-java
					${mysql.driver.version}
				
				
				
					org.apereo.cas
					cas-server-support-redis-ticket-registry
					${cas.version}
				
				
				
					org.apereo.cas
					cas-server-core-webflow
					${cas.version}
				
				
				
					org.apereo.cas
					cas-server-core-authentication
					${cas.version}
				
				
					org.apereo.cas
					cas-server-core-authentication-api
					${cas.version}
				
				
					org.apereo.cas
					cas-server-core-webflow-api
					${cas.version}
				
				
					org.apereo.cas
					cas-server-core-configuration
					${cas.version}
				
				
				
					com.github.penggle
					kaptcha
					2.3.2
				
				
				
				
					org.apereo.cas
					cas-server-support-audit-jdbc
					${cas.version}
					runtime
				
			
		

		
			
				false
			
			exec
			
				org.apereo.cas.web.CasWebApplication
				true
				
			
			
				
					
						com.soebes.maven.plugins
						echo-maven-plugin
						0.3.0
						
							
								prepare-package
								
									echo
								
							
						
						
							
								Executable profile to make the generated CAS web
									application executable.
							
						
					
				
			
		

		
			
				false
			
			bootiful
			
				-tomcat
				false
			
			
				
					org.apereo.cas
					cas-server-webapp${app.server}
					${cas.version}
					war
					runtime
				
			
		

		
			
				false
			
			pgp
			
				
					
						com.github.s4u.plugins
						pgpverify-maven-plugin
						1.1.0
						
							
								
									check
								
							
						
						
							hkp://pool.sks-keyservers.net
							${settings.localRepository}/pgpkeys-cache
							test
							true
							false
						
					
				
			
		
	

效果展示:

Cas5.3.2之自定义登入流程(实现验证码)_第3张图片

你可能感兴趣的:(activiti,流程引擎)