Springboot集成shiro,登录重定向跨域问题

🍅集成方式

项目采用了前后端分离的结构,前端使用的是vue框架,后端使用的是springboot框架,登录认证框架是shiro,同时使用了单点登录。

整个登录认证的逻辑:

  • 通过shiro判断用户是否登陆了
  • 如果没有登录或者登录过期,通过shiro的配置跳转到指定的controller
  • controller中重定向到单点登录页面

🍇问题描述

  • 当登录过期了前端先发送一个请求到接口A
  • shiro判断了用户已经登录过期了,返回状态码302,并让前端重新请求到接口B
  • 在接口B,返回状态码302,并让前端重新请求到单点登录地址
  • 前端重新请求这个单点登录地址
  • 浏览器判断单点登录地址和当前系统地址不是同一个,于是就出现跨域错误

🍈解决思路

这个问题在网上找了很多解决的办法都是通过解决跨域,比如使用注解@CrossOrigin,但是都没有生效。

后来思考了下,跨域是重定向和父页面不同的地址出现的,这个时候在后端怎么配置其实已经没有用了。

现在核心问题,当登录失效之后就不返回状态码302,而是直接调用退出登录接口,这样也能达到重新登录的目的。

🍉源码分析

为了解决这个问题,我们需要先研究一下shiro的源码如何来判断用户登录过期的,并且返回302重定向到新接口的。

在这里插入图片描述

通过上面的时序图可以看出最后调用的是AccesssControlFilter类的onPreHandle方法,这个方法调用了两个方法:isAccessAllowedonAccessDenied

isAccessAllowed:判断用户是否登录,如果登陆了直接返回了,如果没有登录就会执行第二个方法onAccessDenied:是否拒绝登录,在这里面就可以自定义一些返回值

public boolean onPreHandle(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception {
    return isAccessAllowed(request, response, mappedValue) || onAccessDenied(request, response, mappedValue);
}

从这里可以看出,如果我们想自己定义返回值的话就要重写这两个方法。

🍊解决办法

  • 首先定义一个Filter,这个Filter继承AuthorizationFilter,然后重写了isAccessAllowedonAccessDenied

    onAccessDeniedResponse就返回401,前端拿到这个401就请求退出接口

public class RefreshAuthorizationFilter extends AuthorizationFilter {

    private ISecurityService securityService;

    public RefreshAuthorizationFilter(ISecurityService securityService) {
        this.securityService = securityService;
    }

    @Override
    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception {
        return securityService.isLogin();
    }

    @Override
    protected boolean onAccessDenied(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception {
        response.getWriter().write("401");
        return false;
    }
}
  • 使用配置将Filter加入Filter链中,并且加上@Primary注解,这样优先级才会优先执行。
@Primary
@Component
public class RefreshALoginConfig extends ALoginConfig {

    @Autowired
    private ISecurityService securityService;

    @Override
    protected void addFilters() {
        addFilter("restartRefresh", new RefreshAuthorizationFilter(securityService));
    }

    protected void initFilterChainDefinitions() {
        filter("/api/**", "restartRefresh");
    }
}

  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
您好!要在Spring Boot中实现Shiro跨域功能,可以遵循以下步骤: 1. 配置ShiroFilterFactoryBean:在您的Shiro配置类中,使用`ShiroFilterFactoryBean`来配置Shiro的过滤器链。在这个配置中,您可以添加一个`cors`过滤器,并设置允许的跨域资源共享规则。 ```java @Bean public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) { // ... // 其他配置 // ... // 添加Shiro的过滤器 ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); shiroFilterFactoryBean.setSecurityManager(securityManager); // 设置跨域过滤器 LinkedHashMap<String, Filter> filters = new LinkedHashMap<>(); filters.put("cors", corsFilter()); // 自定义的CORS过滤器bean shiroFilterFactoryBean.setFilters(filters); // 设置过滤器链规则 Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>(); filterChainDefinitionMap.put("/**", "cors,authc"); // 设置跨域过滤器和其他过滤器 shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap); return shiroFilterFactoryBean; } ``` 2. 自定义CORS过滤器:创建一个自定义的CORS过滤器,在该过滤器中设置允许的跨域资源共享规则。 ```java public class CorsFilter extends OncePerRequestFilter { @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { // 设置允许的跨域资源共享规则 response.setHeader("Access-Control-Allow-Origin", "*"); response.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS"); response.setHeader("Access-Control-Allow-Headers", "Authorization, Content-Type, X-Requested-With"); filterChain.doFilter(request, response); } } ``` 3. 配置跨域过滤器Bean:将自定义的CORS过滤器配置为一个Spring Bean。 ```java @Bean public CorsFilter corsFilter() { return new CorsFilter(); } ``` 通过以上步骤,您就可以在Spring Boot中实现Shiro跨域功能了。请根据您的具体需求进行适当的调整和配置。希望对您有帮助!如果您有任何问题,请随时提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值