cas 单点登陆实战-sso-config篇(五)

本篇我们讲解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这个方法中,具体方法看代码吧

猜你喜欢

转载自blog.csdn.net/qq_36666181/article/details/81907595