spring boot 2.0 集成 shiro 和 pac4j cas单点登录-Ajax请求携带cookie跨域

spring boot 2.0 集成 shiro 和 pac4j cas单点登录-Ajax请求携带cookie跨域

一、CAS服务端

# CAS官方配置说明 https://apereo.github.io/cas/5.3.x/installation/Configuration-Properties.html
cas:
  httpWebRequest:
    header:
      # 允许使用iframe嵌套CAS登录页面
      xframe: false
    cors:
      # 跨域cookie
      allowCredentials: true
      allowHeaders:
        - '*'
      allowMethods:
        - '*'
      allowOrigins:
        - '*'
      enabled: true
      exposedHeaders:
        - 'Set-Cookie'
      maxAge: 3600

二、CAS客户端

spring boot 2.0 集成 shiro 和 pac4j cas单点登录

1.新建CorsFilter类
package com.ruoyi.framework.shiro.web.filter;

import org.springframework.web.cors.CorsUtils;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;


/**
 * 跨域配置
 */
public class CorsFilter implements Filter {

    /**
     * 增加跨域设置
     */
    @Override
    public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain filterChain) throws IOException, ServletException {

        HttpServletRequest req = (HttpServletRequest) request;
        HttpServletResponse rep = (HttpServletResponse) response;
        if (CorsUtils.isCorsRequest(req)) {
            String origin = req.getHeader("Origin");
            // Access-Control-Allow-Origin的值不要写*号,因为对于带有cookie的跨域请求,浏览器不支持这种宽松的策略
            rep.setHeader("Access-Control-Allow-Origin", origin);
            // 允许的访问方法
            rep.setHeader("Access-Control-Allow-Methods", "POST, GET, PUT, OPTIONS, DELETE, PATCH");
            // Access-Control-Max-Age 用于 CORS 相关配置的缓存
            rep.setHeader("Access-Control-Max-Age", "3600");
            rep.setHeader("Access-Control-Allow-Headers", "token, Accept, Origin, X-Requested-With, Content-Type, Last-Modified");
            // 如果操作cookie,必须加上这句话
            rep.setHeader("Access-Control-Allow-Credentials", "true");
        }

        filterChain.doFilter(request, response);

    }


}

2.修改ShiroConfig
	
    @Bean
    public FilterRegistrationBean corsFilter() {
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
        filterRegistrationBean.setFilter(new CorsFilter());
        filterRegistrationBean.setEnabled(true);
        filterRegistrationBean.addUrlPatterns("/*");
        filterRegistrationBean.setOrder(1);
        return filterRegistrationBean;
    }


    @Bean
    public FilterRegistrationBean filterRegistrationBean() {
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
        filterRegistrationBean.setFilter(new DelegatingFilterProxy("shiroFilter"));
        filterRegistrationBean.addInitParameter("targetFilterLifecycle", "true");
        filterRegistrationBean.setEnabled(true);
        filterRegistrationBean.addUrlPatterns("/*");
        filterRegistrationBean.setOrder(10);
        return filterRegistrationBean;
    }



	/**
     * Shiro过滤器配置
     */
    @Bean
    public ShiroFilterFactoryBean shiroFilter(DefaultWebSecurityManager securityManager, Config config)
    {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        // Shiro的核心安全接口,这个属性是必须的
        shiroFilterFactoryBean.setSecurityManager(securityManager);

        Map<String, Filter> filters = new LinkedHashMap<String, Filter>();

        // cas 资源认证拦截器
        SecurityFilter securityFilter = new SecurityFilter();
        securityFilter.setConfig(config);
        securityFilter.setClients(casProperties.getCasClientName());

        // cas 认证后回调拦截器
        CallbackFilter callbackFilter = new CallbackFilter();
        callbackFilter.setDefaultUrl(casProperties.getCasClientUrl());
        callbackFilter.setConfig(config);

        // 注销 拦截器
        LogoutFilter logoutFilter = new LogoutFilter();
        logoutFilter.setConfig(config);
        logoutFilter.setCentralLogout(true);
        logoutFilter.setLocalLogout(true);
        logoutFilter.setDefaultUrl(casProperties.getCasClientUrl() + "/callback?client_name=" + casProperties.getCasClientName());

        filters.put("onlineSession", onlineSessionFilter());
        filters.put("syncOnlineSession", syncOnlineSessionFilter());
        filters.put("logout",logoutFilter);
        filters.put("callbackFilter", callbackFilter);
        filters.put("securityFilter", securityFilter);

        shiroFilterFactoryBean.setFilters(filters);


        // Shiro连接约束配置,即过滤链的定义
        LinkedHashMap<String, String> filterChainDefinitionMap = new LinkedHashMap<>();

        // 对静态资源设置匿名访问
        filterChainDefinitionMap.put("/favicon.ico**", "anon");
        filterChainDefinitionMap.put("/ruoyi.png**", "anon");
        filterChainDefinitionMap.put("/css/**", "anon");
        filterChainDefinitionMap.put("/docs/**", "anon");
        filterChainDefinitionMap.put("/fonts/**", "anon");
        filterChainDefinitionMap.put("/img/**", "anon");
        filterChainDefinitionMap.put("/images/**", "anon");
        filterChainDefinitionMap.put("/ajax/**", "anon");
        filterChainDefinitionMap.put("/js/**", "anon");
        filterChainDefinitionMap.put("/ruoyi/**", "anon");
        filterChainDefinitionMap.put("/captcha/captchaImage**", "anon");
        filterChainDefinitionMap.put("/webjars/**", "anon");

        filterChainDefinitionMap.put("/callback", "callbackFilter");
        filterChainDefinitionMap.put("/logout", "logout");

        // 所有请求需要认证
        filterChainDefinitionMap.put("/**", "securityFilter,onlineSession,syncOnlineSession");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);

        return shiroFilterFactoryBean;
    }

说明:
注意的是项目加载了哪些filter,它们的顺序是怎样的?这样有利于排查问题。
在CorsFilter#doFilter方法内打断点,watch 变量FilterChain filterChain的值,注意其顺序。

三、ajax调用示例

    $.ajax({
        type:"post",
        async: false,
        url:"http://127.0.0.1:80/system/userInfo",
        data: {},
        // 携带cookie
        xhrFields: {
            withCredentials: true
        },
        crossDomain:true,
        dataType: 'json',
        success:function(data, textStatus, jqXHR) {
            console.log(data);
        },
        error: function(xhr, textStatus, e) {
            console.log(textStatus);
        }
    });

注意:新版本的Chrome浏览器,默认禁用跨域携带cookie,可以手动设置浏览器chrome://flags/ 搜索SameSite设置项并禁用(不建议)。可以使用nginx代理各系统,解决同源问题。

参考
解决在CAS中的跨域请求问题
Refused to display ‘url’ in a frame because it set ‘X-Frame-Options’ to ‘deny’

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

搬山境KL攻城狮

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值