Skip to content
PlatformShiroWebConfiguration.java 10 KiB
Newer Older
杨郁彬's avatar
杨郁彬 committed
/**
 * <p>上海中信信息发展股份有限公司 Copyright(c) 2019</p>
 * <p>http://www.cesgroup.com.cn/</p>
 * <p>2019-5-13 21:25 by 大数据创建中心</p>
 */
package com.cesgroup.kingkong.autoconfigure.shiro;

import com.cesgroup.kingkong.autoconfigure.jcaptcha.PlatformJCaptchaProperties;
import com.cesgroup.kingkong.core.security.service.AuthenticateService;
import com.cesgroup.kingkong.core.security.service.AuthsystemService;
import com.cesgroup.kingkong.core.security.service.CryptoService;
import com.cesgroup.kingkong.shiro.ShiroConstants;
import com.cesgroup.kingkong.shiro.ShiroUtils;
import com.cesgroup.kingkong.shiro.authc.PlatformRetryLimitCredentialsMatcher;
import com.cesgroup.kingkong.shiro.config.ShiroFilterChainDefinitionBuilder;
import com.cesgroup.kingkong.shiro.config.ShiroWebConfigurer;
import com.cesgroup.kingkong.shiro.config.ShiroWebFiltersBuilder;
import com.cesgroup.kingkong.shiro.filter.PlatformFormAuthenticationFilter;
import com.cesgroup.kingkong.shiro.filter.PlatformPermFilter;
import com.cesgroup.kingkong.shiro.filter.PlatformRoleFilter;
import com.cesgroup.kingkong.shiro.filter.PlatformSessionControllerFilter;
import com.cesgroup.kingkong.shiro.filter.PlatformUserFilter;
import com.cesgroup.kingkong.shiro.jcaptcha.JCaptchaFilter;
import com.cesgroup.kingkong.shiro.realm.LoginnamePasswordRealm;
import com.cesgroup.kingkong.shiro.realm.UsernamePasswordRealm;
import com.cesgroup.kingkong.shiro.service.PlatformAuthenticateService;
import com.cesgroup.kingkong.shiro.service.ShiroAuthenticateService;
import com.cesgroup.kingkong.shiro.service.ShiroServiceDelegate;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.lang.Nullable;

import java.util.Optional;

/**
 * Shiro Web配置
 *
 * @author 数据创建中心
 * @version 1.0.0 2019-5-13
 */
@Configuration
@ConditionalOnMissingBean(name = "filterShiroFilterRegistrationBean")
public class PlatformShiroWebConfiguration extends AbstractShiroBaseWebConfiguration {

	protected final ShiroWebConfigurer configurer;

	@Nullable
	protected final PlatformJCaptchaProperties jcatpchaProperties;

	protected final CryptoService cryptoService;

	protected final AuthenticateService authenticateService;

	protected final @Nullable
	AuthsystemService authsystemService;

	/**
	 * 构造函数
	 *
	 * @param properties          配置项
	 * @param configurer          ShiroWeb自定义配置
	 * @param jcaptchaProperties  JCaptcha配置项
	 * @param cryptoService       密码接口
	 * @param authenticateService 认证接口
	 * @param authsystemService   系统管理接口
	 */
	public PlatformShiroWebConfiguration(PlatformShiroProperties properties,
																			 ObjectProvider<ShiroWebConfigurer> configurer,
																			 ObjectProvider<PlatformJCaptchaProperties> jcaptchaProperties,
																			 CryptoService cryptoService, AuthenticateService authenticateService,
																			 ObjectProvider<AuthsystemService> authsystemService) {
		super(properties);
		this.configurer = configurer.getIfAvailable();
		this.jcatpchaProperties = jcaptchaProperties.getIfAvailable();
		synchronized (ShiroUtils.class) {
			ShiroUtils.AJAX_ERROR_STATUS = properties.getAjaxErrorStatus();
		}
		//构造函数初始化,保证能使用
		this.cryptoService = cryptoService;
		this.authenticateService = authenticateService;
		this.authsystemService = authsystemService.getIfAvailable();
	}

	/**
	 * Shiro服务代理
	 *
	 * @return Shiro服务代理
	 */
	@Bean
	@ConditionalOnMissingBean
	public ShiroServiceDelegate shiroService() {
		ShiroServiceDelegate service = new ShiroServiceDelegate();
		service.setAuthenticateService(shiroAuthenticateService());
		service.setCryptoService(cryptoService);
		service.setAuthsystemService(authsystemService);
		return service;
	}

	/**
	 * Shiro认证服务
	 *
	 * @return Shiro认证服务
	 */
	@Bean
	@ConditionalOnMissingBean
	public ShiroAuthenticateService shiroAuthenticateService() {
		PlatformAuthenticateService shiroAuthenticateService = new PlatformAuthenticateService();
		shiroAuthenticateService.setAuthenticateService(this.authenticateService);
		return shiroAuthenticateService;
	}

	/**
	 * 默认的用户名密码认证器
	 *
	 * @param service Shiro服务代理
	 * @return LoginnamePasswordRealm
	 */
	@Bean
	public UsernamePasswordRealm loginnamePasswordRealm(final ShiroServiceDelegate service) {
		UsernamePasswordRealm realm = new LoginnamePasswordRealm();
		//密码管理器
		PlatformRetryLimitCredentialsMatcher matcher = new PlatformRetryLimitCredentialsMatcher(cacheManager);
		matcher.setShiroService(service);
		matcher.setIsLockAccout(properties.getLockAccount());
		matcher.setRetryMaxCount(properties.getRetryMaxCount());

		realm.setCredentialsMatcher(matcher);
		realm.setShiroService(service);
		//使用缓存
		realm.setCachingEnabled(true);
		realm.setAuthenticationCachingEnabled(true);
		realm.setAuthenticationCacheName(Optional.ofNullable(properties.getAuthenticationCache())
			.map(c -> c.getName()).orElse(ShiroConstants.CACHE_AUTHENTICATION));
		realm.setAuthorizationCachingEnabled(true);
		realm.setAuthorizationCacheName(Optional.ofNullable(properties.getAuthorizationCache())
			.map(c -> c.getName()).orElse(ShiroConstants.CACHE_AUTHORIZATION));
		return realm;
	}

	/**
	 * 默认的用户名密码认证器
	 *
	 * @param service Shiro服务代理
	 * @return UsernamePasswordRealm
	 */
	@Bean
	@ConditionalOnMissingBean
	public UsernamePasswordRealm usernamePasswordRealm(final ShiroServiceDelegate service) {
		UsernamePasswordRealm realm = new UsernamePasswordRealm();
		//密码管理器
		PlatformRetryLimitCredentialsMatcher matcher = new PlatformRetryLimitCredentialsMatcher(cacheManager);
		matcher.setShiroService(service);
		matcher.setIsLockAccout(properties.getLockAccount());
		matcher.setRetryMaxCount(properties.getRetryMaxCount());

		realm.setCredentialsMatcher(matcher);
		realm.setShiroService(service);
		//使用缓存
		realm.setCachingEnabled(true);
		realm.setAuthenticationCachingEnabled(true);
		realm.setAuthenticationCacheName(Optional.ofNullable(properties.getAuthenticationCache())
			.map(c -> c.getName()).orElse(ShiroConstants.CACHE_AUTHENTICATION));
		realm.setAuthorizationCachingEnabled(true);
		realm.setAuthorizationCacheName(Optional.ofNullable(properties.getAuthorizationCache())
			.map(c -> c.getName()).orElse(ShiroConstants.CACHE_AUTHORIZATION));
		return realm;
	}

	/**
	 * authc认证的过滤器
	 *
	 * @return authc认证的过滤器
	 */
	public PlatformFormAuthenticationFilter authcFilter() {
		PlatformFormAuthenticationFilter filter = new PlatformFormAuthenticationFilter();
		filter.setBehavior(behaviors);
		filter.setSubmitUrl(properties.getSubmitUrl());
		filter.setUsernameParam(properties.getUsernameParam());
		filter.setPasswordParam(properties.getPasswordParam());
		filter.setRememberMeParam(properties.getRememberMeParam());
		filter.setFailureKeyAttribute(properties.getFailureKey());
		return filter;
	}

	/**
	 * 用户并发控制的过滤器
	 *
	 * @return 用户并发控制的过滤器
	 */
	public PlatformSessionControllerFilter sessionControllerFilter() {
		PlatformSessionControllerFilter filter = new PlatformSessionControllerFilter(cacheManager);
		filter.setSessionManager(sessionManager());
		filter.setMaxSession(properties.getMaxSession());
		filter.setForceLogoutUrl(properties.getKickoutUrl());
		filter.setForceLogoutAfter(properties.isKickoutLast());
		return filter;
	}

	/**
	 * 用户并发控制的过滤器
	 *
	 * @return 用户并发控制的过滤器
	 */
	public PlatformUserFilter userFilter() {
		PlatformUserFilter filter = new PlatformUserFilter();
		return filter;
	}

	/**
	 * 单个角色鉴权过滤器
	 *
	 * @return 单个角色鉴权过滤器
	 */
	public PlatformRoleFilter roleFilter() {
		PlatformRoleFilter filter = new PlatformRoleFilter();
		return filter;
	}

	/**
	 * 单个资源鉴权过滤器
	 *
	 * @return 单个资源鉴权过滤器
	 */
	public PlatformPermFilter permFilter() {
		PlatformPermFilter filter = new PlatformPermFilter();
		return filter;
	}

	/**
	 * 验证码过滤器
	 *
	 * @return 验证码过滤器
	 */
	public JCaptchaFilter jcaptchaFilter() {
		JCaptchaFilter filter = new JCaptchaFilter();
		filter.setJcaptchaParam(properties.getJcaptchaParam());
		filter.setFailureKeyAttribute(properties.getFailureKey());
		return filter;
	}

	/**
	 * @see AbstractShiroBaseWebConfiguration
	 * #configureFilter(com.cesgroup.kingkong.shiro.config.ShiroWebFiltersBuilder)
	 */
	@Override
	protected void configureFilter(final ShiroWebFiltersBuilder builder) {
		super.configureFilter(builder);
		builder.filter(ShiroConstants.FILTER_AUTHC, authcFilter());
		builder.filter(ShiroConstants.FILTER_SESSION_CONTROLLER, sessionControllerFilter());
		builder.filter(ShiroConstants.FILTER_USER, userFilter());
		builder.filter(ShiroConstants.FILTER_ROLE, roleFilter());
		builder.filter(ShiroConstants.FILTER_PERM, permFilter());
		if (properties.isJcaptchaEnable() && jcatpchaProperties != null) {
			builder.filter(ShiroConstants.FILTER_JCAPTCHA, jcaptchaFilter());
		}
		if (configurer != null) {
			configurer.configureFilter(builder);
		}
	}

	/**
	 * @see AbstractShiroBaseWebConfiguration
	 * #configureFilterChainDefinition(com.cesgroup.kingkong.shiro.config.ShiroFilterChainDefinitionBuilder)
	 */
	@Override
	protected void configureFilterChainDefinition(final ShiroFilterChainDefinitionBuilder builder) {
		super.configureFilterChainDefinition(builder);
		builder.defaultPath(ShiroConstants.FILTER_USER + "," + ShiroConstants.FILTER_SESSION_CONTROLLER);
		if (properties.isJcaptchaEnable() && jcatpchaProperties != null) {
			builder.path(properties.getSubmitUrl(), ShiroConstants.FILTER_JCAPTCHA + "," + ShiroConstants.FILTER_AUTHC)
				.path(jcatpchaProperties.getRequestUri(), ShiroConstants.FILTER_ANON);
		}
		if (configurer != null) {
			if (configurer.isReplaceChain()) {
				builder.clear();
			}
			configurer.configureFilterChainDefinition(builder);
		}
	}
}