问题:前后端分离项目,在用Shiro做权限控制时,未登录状态发送的请求都会重定向,导致前端无法捕捉重定向后的消息。如何不重定向在原来的请求返回信息提示未登录,前端根据信息调到登录页?

首先,看一下Shiro是在哪里做的重定向。下面是Shiro的部分源码

package org.apache.shiro.web.filter.authc;

public class FormAuthenticationFilter extends AuthenticatingFilter {
protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
if (isLoginRequest(request, response)) {
if (isLoginSubmission(request, response)) {
if (log.isTraceEnabled()) {
log.trace("Login submission detected. Attempting to execute login.");
}
return executeLogin(request, response);
} else {
if (log.isTraceEnabled()) {
log.trace("Login page view.");
}
//allow them to see the login page ;)
return true;
}
} else {
if (log.isTraceEnabled()) {
log.trace("Attempting to access a path which requires authentication. Forwarding to the " +
"Authentication url [" + getLoginUrl() + "]");
}
// 这里做的重定向
saveRequestAndRedirectToLogin(request, response);
return false;
}
} }

发现是FormAuthenticationFilter.onAccessDenied()中做的重定向。接下来就就可以着手解决问题了。

解决:

1. 继承FormAuthenticationFilter,重写onAccessDenied方法

/**
* 继承FormAuthenticationFilter,重写onAccessDenied方法
*/
public class ShiroFormAuthenticationFilter extends FormAuthenticationFilter {
private static final Logger log = LoggerFactory.getLogger(ShiroFormAuthenticationFilter.class); @Override
protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
if (this.isLoginRequest(request, response)) {
if (this.isLoginSubmission(request, response)) {
if (log.isTraceEnabled()) {
log.trace("Login submission detected. Attempting to execute login.");
} return this.executeLogin(request, response);
} else {
if (log.isTraceEnabled()) {
log.trace("Login page view.");
} 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;
} else {
if (log.isTraceEnabled()) {
log.trace("Attempting to access a path which requires authentication. Forwarding to the Authentication url [{}]" ,this.getLoginUrl());
}
/**
* 在这里实现自己想返回的信息,其他地方和源码一样就可以了
*/
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");
DataResponse<?> result = DataResponse.failed(ExceptionCode.NO_AUTH);
PrintWriter out = resp.getWriter();
out.println(JsonUtils.objectToJson(result));
out.flush();
out.close();
return false;
}
}
} }

2. 在config中配置filter

@Configuration
public class ShiroConfig { private static final Logger log = LoggerFactory.getLogger(ShiroConfig.class);
private static Map<String, String> filterChainDefinitionMap = new LinkedHashMap(); @Bean(name = "shiroFilter")
public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilterFactory = new ShiroFilterFactoryBean();
shiroFilterFactory.setSecurityManager(securityManager); filterChainDefinitionMap.put("/sys/login","anon");
filterChainDefinitionMap.put("/captcha.jpg", "anon");
filterChainDefinitionMap.put("/favicon.ico", "anon");
filterChainDefinitionMap.put("/logout","anon");
filterChainDefinitionMap.put("/index","anon");
filterChainDefinitionMap.put("/css/**","anon");
filterChainDefinitionMap.put("/js/**","anon");
filterChainDefinitionMap.put("/img/**","anon");
filterChainDefinitionMap.put("/fonts/**","anon");
filterChainDefinitionMap.put("/chosen/**","anon");
filterChainDefinitionMap.put("/static/**","anon");
filterChainDefinitionMap.put("/swagger-ui.html","anon");
filterChainDefinitionMap.put("/swagger-ui.html/**","anon");
filterChainDefinitionMap.put("/webjars/**","anon");
filterChainDefinitionMap.put("/layout/**","anon");
filterChainDefinitionMap.put("/swagger-resources/**","anon");
filterChainDefinitionMap.put("/v2/**","anon");
filterChainDefinitionMap.put("/**","authc");
LinkedHashMap<String, Filter> filtsMap = new LinkedHashMap<>();
// 这里使用自定义的filter
filtsMap.put("authc", new ShiroFormAuthenticationFilter());
shiroFilterFactory.setFilters(filtsMap);
shiroFilterFactory.setFilterChainDefinitionMap(filterChainDefinitionMap);
return shiroFilterFactory;
}
}

OK,问题解决。

附注:

servlet的两种跳转方式:forward转发、redirect重定向

两者的区别:

1.地址栏

1)forward是服务器内部的跳转,服务器直接访问目标地址,客户端不知情,因此浏览器的网址不发生变化

2)redirect是服务器根据逻辑,发送一个状态码,告诉浏览器重新去请求另一个地址,所以地址栏显示新的地址

2.数据共享

forward在整个跳转过程中用的是同一个request,forward会将request的信息带到被跳转的jsp或者是servlet中使用,所以数据是共享的。而redirect是新的request,所以数据不共享。

3.运用

1) forward一般用于用户登录的时候,根据角色转发到相应的模块

2) redirect一般用于用户注销登录时返回主页或者跳转到其他网站

4.效率

forward效率高,redirect效率低

5.本质

forward转发时服务器上的行为,而redirect重定向是客户端的行为

6.请求次数

forward 一次,redirect两次

Shiro:未登录时请求跳转问题的更多相关文章

  1. dede用户登录时,跳转到提示页时报404错误

    做了一个项目,本地运行,用的是Apache服务器,一切正常. 可是当我把项目放到VPS中运行时,每当输入用户名登录时,调转到"成功登录,3秒钟后转向网站主页"的提示页面时,页面的顶 ...

  2. dotnetnuke 7.x登录时不跳到站点设置中的指定页

    查源码发现登录按钮有参数,点击跳到登录页或者弹窗登录,真正登录后会根据传参的url反回.因为皮肤对像没有相应参数,所以只能去掉参数.我是用js去的,偷个懒吧.如下所示: <script type ...

  3. php实现:当未登录时转到登陆页面

    判断session是否存在,不存在则跳转到登录页面session_start(); if ( !$_SESSION['xxx'] ) {    header("Location: login ...

  4. 实用jstl实现未登录时不能绕过登录界面的效果

    package com.filter; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; ...

  5. 单点登录CAS使用记(五):cas-client不拦截静态资源以及无需登录的请求。

    一.问题在哪? 在配置cas-client中,有这么一段配置: <filter> <filter-name>CAS Filter</filter-name> < ...

  6. 基于redis实现未登录购物车

    springboot 工程 主要说明购物车流程(故将登录用户信息保存至session) 未登录时 将用户临时key 保存至cookie 有不足之处 请大佬指点 项目源码: https://github ...

  7. 自定义HttpModule,用于未登录用户,不弹出Windows认证窗口,而是跳转回SSO站点

    2012年的一篇随笔记录,可以学习到如何自定义HttpModule,而具体里面针对需求开发的代码,可能未必能让大伙了解到什么,可快速扫描而过. using System; using System.W ...

  8. 前后端分离项目shiro的未登录和权限不足

    在前后端分离的项目中.前端代码和后端代码几乎不在同一个目录下,甚至不是在一台服务器上:我这个项目部署在linux.同一台服务器,不同目录下:所有的页面跳转由前台路由,后台只是提供返回的数据: 干货↓  ...

  9. C#-WebForm-Session、Cookie-登录验证(未登录跳至登录界面)、隐藏地址栏传值

    Post 传值(看不见的传值) Get 传值(看得见的传值) Session - 全局变量组 存放位置:服务端 作用:只要里面有内容,那么这个网站中所有的C#端都能访问到这个变量 -- object类 ...

随机推荐

  1. VMware 虚拟机三种网络模式详解

    一.前言 Vmware 为我们提供了三种网络工作模式,分别是:Bridged(桥接模式).NAT(网络地址转换模式).Host-only(仅主机模式). 二.VMware 的几个常见虚拟设备 打开 V ...

  2. Cabloy-CMS:动静结合,解决Hexo痛点问题

    介绍 Cabloy-CMS是什么 Cabloy-CMS是基于CabloyJS全栈业务开发框架开发的"动静结合"的CMS,可以快速构建企业网站.博客.社区.商城等Web应用. 在线演 ...

  3. DirectX12 3D 游戏开发与实战第二章内容

    矩阵代数 学习目标 理解矩阵及其相关运算的定义 探究为何能把向量和矩阵的乘法视为一种线性组合 学习单位矩阵.转置矩阵.行列式以及矩阵的逆等概念 逐步熟悉DirectXMath库中提供的关于矩阵计算的类 ...

  4. 中国知网(CNKI)验证码识别

    中国知网(CNKI)是最重要的中文学术资源数据库,收录绝大多数中文学术刊物.我们可以检索论文,也可以导出检索结果前6000条论文的题录数据. 在CNKI检索结果翻页10次以上,用户需要手动输入验证码才 ...

  5. HTML定位和布局----float浮动

    1.定位体系一共有三种 (1)常规流: (2)浮动定位 (3)绝对定位 2.float属性常用的语法: (1)float:left:左浮动 (2)float:right:右浮动 (3)float:no ...

  6. Android的显示意图和隐式意图总结

    显示意图 简而言之: 通过指定特定Activity的包名和类名开启Activity 应用场景: 一般应用于本App内的activity间的跳转. XML配置信息: AndroidManifest.xm ...

  7. Vue-学习笔记0-独立项目搭建

    前言 搭建Vue+Webpack项目,使用vue-cli搭建项目. 准备 vue独立项目依赖node的npm包管理器,所以需要先安装node. 相关的npm常用命令文章: Npm-常用命令,点击访问 ...

  8. 使用uEdit时,在线管理图片功能不可用

    把所有的配置文件都配置好了,uedit的在线管理功能图片还是不可用,看了一下源码: 是的,它在img的src属性后边的图片上加上了参数,那肯定不能用啊,所以修改源文件image.js.直接搜索noCa ...

  9. Python 编译器与解释器

    Python 编译器与解释器 Python的环境我们已经搭建好了,可以开始学习基础知识了.但是,在此之前,还要先说说编译器与解释器相关的内容. 如果这部分内容,让你觉得难以理解或不能完全明白,可以暂时 ...

  10. 从SpringMVC获取用户信息谈起

    Github地址:https://github.com/andyslin/spring-ext 编译.运行环境:JDK 8 + Maven 3 + IDEA + Lombok spring-boot: ...