cas 單點登陸實戰-sso-config篇(五)
阿新 • • 發佈:2018-11-02
本篇我們講解cas單點登陸在與shiro整合,在與redis整合遇到的問題
先看完整程式碼吧
package com.madnet.config; import com.google.common.base.CaseFormat; import com.madnet.module.permission.repository.PermissionRepository; import com.madnet.module.permission.service.PermissionService; import io.buji.pac4j.filter.CallbackFilter; import io.buji.pac4j.filter.LogoutFilter; import io.buji.pac4j.filter.SecurityFilter; import io.buji.pac4j.realm.Pac4jRealm; import io.buji.pac4j.subject.Pac4jSubjectFactory; import org.apache.shiro.codec.Base64; import org.apache.shiro.mgt.DefaultSecurityManager; import org.apache.shiro.mgt.SecurityManager; import org.apache.shiro.realm.Realm; import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor; import org.apache.shiro.spring.web.ShiroFilterFactoryBean; import org.apache.shiro.spring.web.config.AbstractShiroWebFilterConfiguration; import org.apache.shiro.spring.web.config.DefaultShiroFilterChainDefinition; import org.apache.shiro.spring.web.config.ShiroFilterChainDefinition; import org.apache.shiro.web.mgt.CookieRememberMeManager; import org.apache.shiro.web.mgt.DefaultWebSecurityManager; import org.apache.shiro.web.servlet.SimpleCookie; import org.apache.shiro.web.session.mgt.DefaultWebSessionManager; import org.apache.tomcat.util.descriptor.web.FilterMap; import org.crazycake.shiro.RedisManager; import org.crazycake.shiro.RedisSessionDAO; import org.jasig.cas.client.authentication.AuthenticationFilter; import org.pac4j.cas.client.CasClient; import org.pac4j.cas.client.rest.CasRestFormClient; import org.pac4j.cas.config.CasConfiguration; import org.pac4j.cas.config.CasProtocol; import org.pac4j.core.client.Clients; import org.pac4j.core.config.Config; import org.pac4j.core.matching.PathMatcher; import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.DependsOn; import org.springframework.web.filter.DelegatingFilterProxy; import javax.servlet.Filter; import javax.servlet.FilterConfig; import java.awt.*; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Map; import org.apache.shiro.cas.CasFilter; import org.crazycake.shiro.RedisCacheManager; /** * 對shiro的安全配置,是對cas的登入策略進行配置 * * @author Carl * @date 2017/9/16 * @since 1.0.0 */ @Configuration public class ShiroConfiguration extends AbstractShiroWebFilterConfiguration { @Value("#{ @environment['cas.prefixUrl'] ?: null }") private String prefixUrl; @Value("#{ @environment['cas.loginUrl'] ?: null }") private String casLoginUrl; @Value("#{ @environment['cas.callbackUrl'] ?: null }") private String callbackUrl; @Value("#{ @environment['cas.serviceUrl'] ?: null }") private String serviceUrl; @Autowired private PermissionService permissionService; @Value("${spring.redis.host}") private String host; @Value("${spring.redis.port}") private int port; @Value("${spring.redis.timeout}") private String timeout; /** * cas核心過濾器,把支援的client寫上,filter過濾時才會處理,clients必須在casConfig.clients已經註冊 * * @return */ @Bean public Filter casSecurityFilter() { SecurityFilter filter = new SecurityFilter(); filter.setClients("cas,rest"); filter.setConfig(casConfig()); return filter; } /** * 通過rest介面可以獲取tgt,獲取service ticket,甚至可以獲取CasProfile * * @return */ @Bean protected CasRestFormClient casRestFormClient() { CasRestFormClient casRestFormClient = new CasRestFormClient(); casRestFormClient.setConfiguration(casConfiguration()); casRestFormClient.setName("rest"); return casRestFormClient; } @Bean public PathMatcher pathMatcher() { PathMatcher pathMatcher = new PathMatcher(); pathMatcher.excludePath("/**"); return pathMatcher; } @Bean protected Clients clients() { //可以設定預設client Clients clients = new Clients(); //支援的client全部設定進去 clients.setClients(casClient(), casRestFormClient()); return clients; } @Bean public CasClient casClient() { CasClient casClient = new CasClient(); casClient.setConfiguration(casConfiguration()); casClient.setCallbackUrl(callbackUrl); casClient.setName("cas"); return casClient; } @Bean protected Config casConfig() { Config config = new Config(); config.setClients(clients()); return config; } /** * cas的基本設定,包括或url等等,rest呼叫協議等 * * @return */ @Bean public CasConfiguration casConfiguration() { CasConfiguration casConfiguration = new CasConfiguration(casLoginUrl); casConfiguration.setProtocol(CasProtocol.CAS30); casConfiguration.setPrefixUrl(prefixUrl); return casConfiguration; } /** * 路徑過濾設定 * * @return */ @Bean public ShiroFilterChainDefinition shiroFilterChainDefinition() { DefaultShiroFilterChainDefinition definition = new DefaultShiroFilterChainDefinition(); definition.addPathDefinition("/login2", "casSecurityFilter"); definition.addPathDefinition("/login.jsp", "casSecurityFilter"); definition.addPathDefinition("/callback", "callbackFilter"); definition.addPathDefinition("/logout", "logoutFilter"); return definition; } @Bean protected Map<String, Filter> shiroFilters() { //過濾器設定 Map<String, Filter> filters = new HashMap<>(); filters.put("casSecurityFilter", casSecurityFilter()); CallbackFilter callbackFilter = new CallbackFilter(); callbackFilter.setConfig(casConfig()); filters.put("callbackFilter", callbackFilter); LogoutFilter logoutFilter = new LogoutFilter(); logoutFilter.setConfig(casConfig()); logoutFilter.setCentralLogout(true); logoutFilter.setDefaultUrl(serviceUrl); filters.put("logoutFilter", logoutFilter); return filters; } @Bean public Realm pac4jRealm() { return new RealmConfiguration(); } @Bean public SecurityManager securityManager() { DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); securityManager.setSubjectFactory(new Pac4jSubjectFactory()); securityManager.setRealm(pac4jRealm()); // securityManager.setSessionManager(SessionManager()); // securityManager.setCacheManager(cacheManager()); return securityManager; } @Bean(name = "casFilter") public CasFilter getCasFilter() { CasFilter casFilter = new CasFilter(); casFilter.setName("casFilter"); casFilter.setEnabled(true); casFilter.setLoginUrl("/login2"); // 登入失敗後跳轉的URL,也就是 Shiro 執行 CasRealm 的 doGetAuthenticationInfo 方法向CasServer驗證tiket casFilter.setFailureUrl(loginUrl);// 我們選擇認證失敗後再開啟登入頁面 return casFilter; } /** * 對過濾器進行調整 * * @return */ @Bean("shiroFilter") protected ShiroFilterFactoryBean shiroFilterFactoryBean() { ((DefaultSecurityManager) securityManager).setSubjectFactory(new Pac4jSubjectFactory()); ShiroFilterFactoryBean filterFactoryBean = super.shiroFilterFactoryBean(); filterFactoryBean.setSecurityManager(securityManager); filterFactoryBean.setFilters(shiroFilters()); Map<String, String> initParameters = new HashMap(); initParameters.put("/callback","callbackFilter"); initParameters.put("/logout","logoutFilter"); // initParameters.put("/upload.html", "casSecurityFilter"); initParameters.put("/static/**", "anon"); initParameters.put("/upload.html", "authc"); initParameters.putAll(permissionService.getAuthcMap()); filterFactoryBean.setFilterChainDefinitionMap(initParameters); filterFactoryBean.setLoginUrl("/login2"); // 登入成功後要跳轉的連結 filterFactoryBean.setSuccessUrl("/index.html"); // 未授權介面; filterFactoryBean.setUnauthorizedUrl("/login2"); return filterFactoryBean; } /** * 對shiro的過濾策略進行明確 * * @return */ @Bean public FilterRegistrationBean delegatingFilterProxy() { FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(); DelegatingFilterProxy proxy = new DelegatingFilterProxy(); proxy.setTargetFilterLifecycle(true); proxy.setTargetBeanName("shiroFilter"); filterRegistrationBean.setFilter(proxy); return filterRegistrationBean; } /** * 開啟 shiro aop註解支援 * * @param securityManager * @return */ @Bean public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) { AuthorizationAttributeSourceAdvisor aasa = new AuthorizationAttributeSourceAdvisor(); aasa.setSecurityManager(securityManager); return aasa; } @Bean public FilterRegistrationBean someFilterRegistration() { FilterRegistrationBean registration = new FilterRegistrationBean(); registration.setFilter(casSecurityFilter()); registration.addUrlPatterns("/login2"); registration.setName("casSecurityFilter"); return registration; } @Bean public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator() { DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator(); advisorAutoProxyCreator.setProxyTargetClass(true); return advisorAutoProxyCreator; } /** * 配置shiro redisManager * * @return */ @Bean public RedisManager redisManager() { RedisManager redisManager = new RedisManager(); redisManager.setHost(host); redisManager.setPort(port); redisManager.setExpire(18000);// 配置過期時間 //redisManager.setTimeout(Integer.parseInt(timeout)); // redisManager.setPassword(String.valueOf(password)); return redisManager; } /** * cacheManager 快取 redis實現 * * @return */ @Bean(name="cach") public RedisCacheManager cacheManager() { RedisCacheManager redisCacheManager = new RedisCacheManager(); redisCacheManager.setRedisManager(redisManager()); return redisCacheManager; } /** * RedisSessionDAO shiro sessionDao層的實現 通過redis */ @Bean public RedisSessionDAO redisSessionDAO() { RedisSessionDAO redisSessionDAO = new RedisSessionDAO(); redisSessionDAO.setRedisManager(redisManager()); return redisSessionDAO; } /** * shiro session的管理 */ @Bean public DefaultWebSessionManager SessionManager() { DefaultWebSessionManager sessionManager = new DefaultWebSessionManager(); //sessionManager.setSessionIdCookie(sessionMeCookie()); sessionManager.setSessionDAO(redisSessionDAO()); return sessionManager; } @Bean public SimpleCookie sessionMeCookie() { SimpleCookie simpleCookie = new SimpleCookie("madnet-s-org"); simpleCookie.setMaxAge(-1); simpleCookie.setDomain(".mad-net.org"); return simpleCookie; } @Bean public SimpleCookie rememberMeCookie() { // 這個引數是cookie的名稱,對應前端的checkbox的name = rememberMe SimpleCookie simpleCookie = new SimpleCookie("madnet-re-org"); simpleCookie.setMaxAge(18000); // <!-- 記住我cookie生效時間30天 ,單位秒;--> // simpleCookie.setMaxAge(2592000); simpleCookie.setDomain(".mad-net.org"); return simpleCookie; } }
cas:
prefixUrl: https://172.17.1.10:8443/cas
loginUrl: ${cas.prefixUrl}/login
serviceUrl: http://172.17.1.10:${server.port}
callbackUrl: ${cas.serviceUrl}/callback
jwt:
salt: 12345678901234567890123456789012
debug: true
若想同時使用
setFilterChainDefinitionMap 和
setFilters
你一定要把規則寫到setFilterChainDefinitionMap這個方法中,具體方法看程式碼吧