Spring Shiro配置第三方SSO客户端登录

经过实践的Shiro配置,利用 sSOInterceptor 进行sso登录拦截

配置

@Configuration
public class ShiroConfiguration extends BaseLogger {

    @Autowired(required = false)
    private SSOInterceptor sSOInterceptor;

    @Autowired(required = false)
    private CacheUtils cacheUtils;


    //将自己的验证方式加入容器
    @Bean
    public UserShiroRealm myShiroRealm() {
        //自定义realm,授权+登录
        UserShiroRealm myShiroRealm = new UserShiroRealm();
        //自定义login token类型
        myShiroRealm.setAuthenticationTokenClass(XXAuthenticationToken.class);
        return myShiroRealm;
    }

    //权限管理,配置主要是Realm的管理认证
    @Bean
    public DefaultWebSecurityManager securityManager(UserShiroRealm userShiroRealm) {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(userShiroRealm);

        //web session管理
        DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
        //企业级缓存sessionDao,获取和保存session,这里session将保存到cacheManager中
        sessionManager.setSessionDAO(new EnterpriseCacheSessionDAO());
        //安全管理器设置session控制器
        securityManager.setSessionManager(sessionManager);

        //设置cacheManager,鉴权和session使用同一个cache,因为session为uuid,用户为用户名,不会冲突
        securityManager.setCacheManager(new CacheManager() {
            @Override
            public <K, V> Cache<K, V> getCache(String name) throws CacheException {
                logger.info("get cache:{}", name);
                return new JimdbCache<>(cacheUtils, CacheConstants.shiroCacheKey(""));
            }
        });

        return securityManager;
    }

    //Filter工厂,设置对应的过滤条件和跳转条件
    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(org.apache.shiro.web.mgt.DefaultWebSecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);

        //url拦截权限定义
        Map<String, String> map = new HashMap<>();
        //登出自己控制
        //map.put("/logout","logout");自己控制登出
        //对所有用户认证
        map.put("/**", "authc");
        //静态资源部校验
        map.put("/static/**", "anon");
        map.put("/checkAppOn.html", "anon");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(map);


        //登录地址,首页地址触发sso登录
        shiroFilterFactoryBean.setLoginUrl("/");
        //首页
        shiroFilterFactoryBean.setSuccessUrl("/index");
        //错误页面,认证不通过时跳转
        shiroFilterFactoryBean.setUnauthorizedUrl("/error");

        //自定义登录过滤器,校验登录,不能直接将filter放入Spring中,他会和ShiroFilter同级,造成混乱
        shiroFilterFactoryBean.getFilters().put("authc", new XXAuthenticationFilter(sSOInterceptor));

        return shiroFilterFactoryBean;
    }

    //加入注解的使用,不加入这个注解不生效
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(org.apache.shiro.web.mgt.DefaultWebSecurityManager securityManager) {
        //注解支持,可支持类级、method级权限控制
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }

}

登录校验Filter

public class XXAuthenticationFilter extends AdviceFilter {

    private final static Logger LOGGER = LoggerFactory.getLogger(ErpAuthenticationFilter.class);

    private SSOInterceptor sSOInterceptor;

    public ErpAuthenticationFilter(SSOInterceptor sSOInterceptor) {
        this.sSOInterceptor = sSOInterceptor;
    }


    /**
     * 处理sso登录信息,且可登录,返回true
     *
     * @param srequest
     * @param sresponse
     * @return
     * @throws Exception
     */
    protected boolean preHandle(ServletRequest srequest, ServletResponse sresponse) throws Exception {

        HttpServletRequest request = (HttpServletRequest) srequest;
        HttpServletResponse response = (HttpServletResponse) sresponse;
        try {

            //sSOInterceptor来控制跳转登录sso页
            if (sSOInterceptor.preHandle(request, response, null)) {
                LoginContext loginContext = ActionContext.getLoginContext();
                Subject subject = SecurityUtils.getSubject();
                //没有登录时,自动登录系统
                if(!subject.isAuthenticated()) {
                    subject.login(new ErpAuthenticationToken(loginContext.getAccount(), loginContext));
                }
                return true;
            }
        } catch (Exception e) {
            LOGGER.error("预处理登录信息失败", e);
        }

        //中止处理链条
        return false;
    }
}

登出

@RequestMapping(value = {"/logout", "/login"})
public void logout(HttpServletRequest request, HttpServletResponse response) throws IOException {
    LoginContext loginContext = ActionContext.getLoginContext();
    //删除业务key
    cookieUtils.deleteCookie(response, Profiles.getCookieKey());
    logger.info("用户:{} 退出", loginContext.getAccount());

    //清缓存
    cacheUtils.deleteObject(CacheConstants.manUserShiroCacheKey(loginContext.getAccount()));
    cacheUtils.deleteObject(CacheConstants.manUserMenuCacheKey(loginContext.getAccount()));
    //shiro登出
    Subject subject = SecurityUtils.getSubject();
    subject.logout();
    //清除cookie
    removeCookie(response);

    ErpDotnetInterceptor.toErpLogin(request, response);
}

private void removeCookie(HttpServletResponse response) {
    Cookie cookie = new Cookie(Profiles.getCookieKey(),"");
    cookie.setMaxAge(0);
    response.addCookie(cookie);
}
原文地址:https://www.cnblogs.com/windliu/p/10310577.html