问题:前后端分离项目,在用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. Java使用Optional与Stream来取代if判空逻辑(JDK8以上)

    Java使用Optional与Stream来取代if判空逻辑(JDK8以上) 通过本文你可以用非常简短的代码替代业务逻辑中的判null校验,并且很容易的在出现空指针的时候进行打日志或其他操作. 注:如 ...

  2. 基于python-django框架的支付宝支付案例

    目录 @ 一. 开发前的准备 1. 必须了解的知识 SDK:软件开发工具包,可以为开发者提供快速开发的工具 沙箱环境:也就是测试环境 支付宝支付金额的精度:小数点后两位(面试) 支付宝用的什么加密方式 ...

  3. 有关Spring事务,看这一篇就足够了

    本文将按照声明式事务的五个特性进行介绍: 事务传播机制 事务隔离机制 只读 事务超时 回滚规则 Spring事务传播机制 事务的特性 原子性(Atomicity):事务是一个原子操作,由一系列动作组成 ...

  4. Junit测试Service类方法教程

    Junit测试是很方便的,本博客记录一下Junit测试一些Service接口的方法,这样可以不运行项目,在@Test注解的方法里直接测试 Maven引入jar包: <properties> ...

  5. Java职责链模式

    一.定义 职责链模式,就是将能够处理某类请求事件的一些处理类,类似链条的串联起来.请求在链条上处理的时候,并不知道具体是哪个处理类进行处理的.一定程度上实现了请求和处理的解耦. 实际生活中的经典例子就 ...

  6. 从CAP到zookeeper和eureka对比

    今天看了一篇eureka对比zookeeper的文章,对zookeeper满足CAP中的CP,eureka满足AP产生了一点疑问,故写此篇文章进行一些探讨. 首先我们来看看CAP的定义 Consist ...

  7. 5分钟了解Prometheus

    Prometheus(译:普罗米修斯)用领先的开源监控解决方案为你的指标和警报提供动力(赋能). 1.  概述 1.1.  Prometheus是什么? Prometheus是一个开源的系统监控和警报 ...

  8. commons-beanutils.jar及其支持文件

    下载地址: 链接:https://pan.baidu.com/s/1AtiK3nsk0aBuBfMdNwBVGw 密码:6tul

  9. ORM组件LogORM使用指北

    LogORM是一个对数据库进行对象关系映射的ORM组件.当对数据库进行增删改操作时,组件会自动进行日志记录. 该组件支持.Net平台和.NetCore平台,支持SQL Server.Oracle.My ...

  10. layui table 行按钮事件,启用禁用切换

    {{# ){ }} <a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="forbidden& ...