springBoot前后端分离项目中shiro的302跳转问题

springBoot前后端分离项目shiro的302跳转

项目是使用的springboot ,使用的shiro做的用户鉴权。在前端请求时当用户信息失效,session失效的时候,shiro会重定向到配置的login.jsp 页面,或者是自己配置的logUrl。

因是前后端分离项目,与静态资源文件分离,固重定向后,接着会404。

经过查找网上配置资料,发现302原因是

  • FormAuthenticationFilter中onAccessDenied 方法做了相应处理。那知道问题所在,就可以有解决方了。
  • 重写 onAccessDenied 方法,针对自己的业务做相应处理,然后在加载过滤器配置的时候添加到配置中。

以下是代码

增加类ShiroFormAuthenticationFilter 重新方法

package com.oilpay.wallet.shiro;
import com.alibaba.fastjson.JSONObject;
import com.oilpay.wallet.interceptor.TokenInterceptor;
import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.RequestMethod;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;

/**
 *
 * 重写权限验证问题,登录失效后返回状态码
 *
 */
public class ShiroFormAuthenticationFilter extends FormAuthenticationFilter {
    Logger logger  = LoggerFactory.getLogger(TokenInterceptor.class);
    @Override
    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
        if (isLoginRequest(request, response)) {
            if (isLoginSubmission(request, response)) {
                if (logger.isTraceEnabled()) {
                    logger.trace("Login submission detected.  Attempting to execute login.");
                }
                return executeLogin(request, response);
            } else {
                if (logger.isTraceEnabled()) {
                    logger.trace("Login page view.");
                }
                //allow them to see the login page ;)
                return true;
            }
        } else {
            HttpServletRequest req = (HttpServletRequest)request;
            HttpServletResponse resp = (HttpServletResponse) response;
            if(req.getMethod().equals(RequestMethod.OPTIONS.name())) {
                resp.setStatus(HttpStatus.OK.value());
                return true;
            }

            if (logger.isTraceEnabled()) {
                logger.trace("Attempting to access a path which requires authentication.  Forwarding to the " +
                        "Authentication url [" + getLoginUrl() + "]");
            }
            //前端Ajax请求时requestHeader里面带一些参数,用于判断是否是前端的请求
            String test= req.getHeader("test");
            if (test!= null || req.getHeader("wkcheck") != null) {
                //前端Ajax请求,则不会重定向
                resp.setHeader("Access-Control-Allow-Origin",  req.getHeader("Origin"));
                resp.setHeader("Access-Control-Allow-Credentials", "true");
                resp.setContentType("application/json; charset=utf-8");
                resp.setCharacterEncoding("UTF-8");
                PrintWriter out = resp.getWriter();
                JSONObject result = new JSONObject();
                result.put("message", "登录失效");
                result.put("resultCode", 1000);
                out.println(result);
                out.flush();
                out.close();
            } else {
                saveRequestAndRedirectToLogin(request, response);
            }
            return false;
        }
    }
}

在过滤器配置中添加

@Bean(name="shiroFilter")
    public ShiroFilterFactoryBean shiroFilter(@Qualifier("securityManager") SecurityManager manager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean=new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(manager);
        //配置访问权限
        LinkedHashMap<String, String> filterChainDefinitionMap=new LinkedHashMap<String, String>();
        filterChainDefinitionMap.put("/common/logout", "logout");
        filterChainDefinitionMap.put("/","anon");
        filterChainDefinitionMap.put("/common/login","anon");

        filterChainDefinitionMap.put("/common/*","anon");
        filterChainDefinitionMap.put("/imageVerifyCode/getCode", "anon");
        filterChainDefinitionMap.put("/sendVerifyCode/register", "anon");
        filterChainDefinitionMap.put("/sendVerifyCode/resetLoginPwd", "anon");
        filterChainDefinitionMap.put("/**", "authc"); //表示需要认证才可以访问

        LinkedHashMap<String, Filter> filtsMap=new LinkedHashMap<String, Filter>();
        filtsMap.put("authc",new ShiroFormAuthenticationFilter() );
        shiroFilterFactoryBean.setFilters(filtsMap);
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        return shiroFilterFactoryBean;
    }

至此,可以按照自己的需求做相应处理。

关于shiro 总是302的问题

我的原因是使用了authc,由于autuc对应的过滤器FormAuthenticationFilter中onAccessDenied方法返回的值都为false,所以访问url时会一直进行循环重定向,解决方案:重写onAccessDenied方法,并注入到shiroFiter中。

附上shiro配置文件

<!-- shiroFilter -->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
   <property name="securityManager" ref="securityManager" />
   <!-- 设定角色的登录链接,这里为cas登录页面的链接可配置回调地址  -->
   <!-- 登录地址 -->
   <property name="loginUrl" value="/login.html"/>
   <!-- 登录后跳转到业务页面 -->
   <property name="successUrl" value="/index.do"/>
   <!-- 错误页面 -->
   <property name="unauthorizedUrl" value="/denied.html"/>
   <property name="filters">
      <map>
         <!--将重写了的FormAuthenticationFilter.onAccessDenied方法的类注入到其中-->
         <entry key="authc" value-ref="formAuthenticationFilter"></entry>
      </map>
   </property>
   <property name="filterChainDefinitions">
      <value>
          /login.html=anon
         <!--配置静态资源-->
         /js/**=anon
         /templates/**=anon
         /assets/**=anon
         /css/**=anon
         <!--权限设置-->
         /index.do=authc
         /user/login.do=anon
         /**=authc
        </value>
   </property>
</bean>
<!-- 重写FormAuthenticationFilter的onAccessDenied方法的自定义过滤器 -->
<bean id="formAuthenticationFilter" class="com.jd.risk.giasys.service.realm.filter.MyFilter" />

重写onAccessDenied方法

package com.jd.risk.giasys.service.realm.filter;
import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
/**
 * Created by jianghaisong on 2017/12/17.
 */
public class MyFilter extends FormAuthenticationFilter{
    private Logger log = LoggerFactory.getLogger(MyFilter.class);
    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
       //进行重写,业务逻辑
    }
}

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • Spring boot整合shiro+jwt实现前后端分离

    本文实例为大家分享了Spring boot整合shiro+jwt实现前后端分离的具体代码,供大家参考,具体内容如下 这里内容很少很多都为贴的代码,具体内容我经过了看源码和帖子加了注释.帖子就没用太多的内容 先下载shiro和jwt的jar包 <!-- shiro包 --> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId

  • shiro整合springboot前后端分离

    本文实例为大家分享了shiro整合springboot前后端分离的具体代码,供大家参考,具体内容如下 1.shiro整合springboot的配置 package com.hisi.config; import java.util.LinkedHashMap; import java.util.Map; import javax.servlet.Filter; import org.apache.shiro.session.mgt.eis.MemorySessionDAO; import org

  • Springboot前后端分离项目配置跨域实现过程解析

    项目登录流程如下 用户进入前端登录界面,输入账号密码等,输入完成之后前端发送请求到后端(拦截器不会拦截登录请求),后端验证账号密码等成功之后生成Token并存储到数据库,数据库中包含该Token过期时间,然后返回生成的Token到前端. 前端收到Token,表示登录成功,把这个Token存储本地.然后跳转到用户中心页面,用户中心页面在ajax的请求头中带上Token,跟随请求用户数据接口一起带到后端. 后端通过拦截器拦截到这个请求,去判断这个Token是否有效,有效就放过去做他该做的事情,无效就

  • springBoot前后端分离项目中shiro的302跳转问题

    springBoot前后端分离项目shiro的302跳转 项目是使用的springboot ,使用的shiro做的用户鉴权.在前端请求时当用户信息失效,session失效的时候,shiro会重定向到配置的login.jsp 页面,或者是自己配置的logUrl. 因是前后端分离项目,与静态资源文件分离,固重定向后,接着会404. 经过查找网上配置资料,发现302原因是 FormAuthenticationFilter中onAccessDenied 方法做了相应处理.那知道问题所在,就可以有解决方了

  • IDEA教程创建SpringBoot前后端分离项目示例图解

    目录 创建springboot项目 测试项目 按照MVC格式创建数据库项目 总结 springboot就是简化Spring应用中的初始化配置,快速创建项目而生的. 创建springboot项目 代开idea,点击File->New->Project,弹出如下对话框 输入组织.工程名,选择maven工程,注意:java版本号选择8 可以根据自己项目的需求选择依赖包,系统会自动将这些依赖包写入maven的pom文件,如下选择Spring Web.myBtias.mySQL驱动等.无需担心漏掉依赖包

  • 部署vue+Springboot前后端分离项目的步骤实现

    单页应用 vue经常被用来开发单页应用(SinglePage Web Application,SPA),什么叫做单页应用呢,也就是只有一张web页面的应用,单页应用的跳转只需要刷新局部资源,大大加快的了我们页面的响应速度 前端页面打包 打开vue工程,在项目根目录下创建一个配置文件:vue.config.js,然后在里面写入以下内容: module.exports = { assetsDir: 'static', // 静态资源保存路径 outputDir: 'dist', // 打包后生成的文

  • SpringBoot+MyBatisPlus+Vue 前后端分离项目快速搭建过程(前端篇)

    后端篇 SpringBoot+MyBatisPlus+Vue 前后端分离项目快速搭建[后端篇][快速生成后端代码.封装结果集.增删改查.模糊查找][毕设基础框架] 前端篇 创建vue项目 1.找个文件夹进入命令行,输入:vue create vue-front 2.直接回车,等待片刻,稍微有点小久 3.根据提示指令测试 打开浏览器输入:http://localhost:8080/ 安装所需工具 安装的工具会有点多,为了提供更好的拓展性,可以自主选择安装(不建议),后面的代码中都是使用到了,不安装

  • SpringBoot+MyBatisPlus+Vue 前后端分离项目快速搭建过程(后端)

    数据库准备 data_test.sql: /* SQLyog Enterprise v12.08 (64 bit) MySQL - 5.7.31 : Database - data_test ********************************************************************* */ /*!40101 SET NAMES utf8 */; /*!40101 SET SQL_MODE=''*/; /*!40014 SET @OLD_UNIQUE_

  • SpringBoot+mybatis+Vue实现前后端分离项目的示例

    目录 一.SpringBoot环境搭建 1.项目的数据库 2.项目所需依赖 3.application.yml文件 4.入口类 二.vue实现前后端分离 1.前端页面 2.springBoot控制层 3.mapper文件 4.项目完整源代码 vue前后端分离实现功能:员工的增删改(先实现数据回显之后,再进行修改)查 一.SpringBoot环境搭建 1.项目的数据库 /* Navicat Premium Data Transfer Source Server : windows Source S

  • Vue+SpringBoot前后端分离中的跨域问题

    在前后端分离开发中,需要前端调用后端api并进行内容显示,如果前后端开发都在一台主机上,则会由于浏览器的同源策略限制,出现跨域问题(协议.域名.端口号不同等),导致不能正常调用api接口,给开发带来不便. 封装api请求 import axios from 'axios' //axios.create创建一个axios实例,并对该实例编写配置,后续所有通过实例发送的请求都受当前配置约束 const $http = axios.create({ baseURL: '', timeout: 1000

  • vue+springboot前后端分离实现单点登录跨域问题解决方法

    最近在做一个后台管理系统,前端是用时下火热的vue.js,后台是基于springboot的.因为后台系统没有登录功能,但是公司要求统一登录,登录认证统一使用.net项目组的认证系统.那就意味着做单点登录咯,至于不知道什么是单点登录的同学,建议去找一下万能的度娘. 刚接到这个需求的时候,老夫心里便不屑的认为:区区登录何足挂齿,但是,开发的过程狠狠的打了我一巴掌(火辣辣的一巴掌)...,所以这次必须得好好记录一下这次教训,以免以后再踩这样的坑. 我面临的第一个问题是跨域,浏览器控制台直接报CORS,

随机推荐