Shiro:未登录时请求跳转问题
问题:前后端分离项目,在用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:未登录时请求跳转问题的更多相关文章
- dede用户登录时,跳转到提示页时报404错误
做了一个项目,本地运行,用的是Apache服务器,一切正常. 可是当我把项目放到VPS中运行时,每当输入用户名登录时,调转到"成功登录,3秒钟后转向网站主页"的提示页面时,页面的顶 ...
- dotnetnuke 7.x登录时不跳到站点设置中的指定页
查源码发现登录按钮有参数,点击跳到登录页或者弹窗登录,真正登录后会根据传参的url反回.因为皮肤对像没有相应参数,所以只能去掉参数.我是用js去的,偷个懒吧.如下所示: <script type ...
- php实现:当未登录时转到登陆页面
判断session是否存在,不存在则跳转到登录页面session_start(); if ( !$_SESSION['xxx'] ) { header("Location: login ...
- 实用jstl实现未登录时不能绕过登录界面的效果
package com.filter; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; ...
- 单点登录CAS使用记(五):cas-client不拦截静态资源以及无需登录的请求。
一.问题在哪? 在配置cas-client中,有这么一段配置: <filter> <filter-name>CAS Filter</filter-name> < ...
- 基于redis实现未登录购物车
springboot 工程 主要说明购物车流程(故将登录用户信息保存至session) 未登录时 将用户临时key 保存至cookie 有不足之处 请大佬指点 项目源码: https://github ...
- 自定义HttpModule,用于未登录用户,不弹出Windows认证窗口,而是跳转回SSO站点
2012年的一篇随笔记录,可以学习到如何自定义HttpModule,而具体里面针对需求开发的代码,可能未必能让大伙了解到什么,可快速扫描而过. using System; using System.W ...
- 前后端分离项目shiro的未登录和权限不足
在前后端分离的项目中.前端代码和后端代码几乎不在同一个目录下,甚至不是在一台服务器上:我这个项目部署在linux.同一台服务器,不同目录下:所有的页面跳转由前台路由,后台只是提供返回的数据: 干货↓ ...
- C#-WebForm-Session、Cookie-登录验证(未登录跳至登录界面)、隐藏地址栏传值
Post 传值(看不见的传值) Get 传值(看得见的传值) Session - 全局变量组 存放位置:服务端 作用:只要里面有内容,那么这个网站中所有的C#端都能访问到这个变量 -- object类 ...
随机推荐
- Java使用Optional与Stream来取代if判空逻辑(JDK8以上)
Java使用Optional与Stream来取代if判空逻辑(JDK8以上) 通过本文你可以用非常简短的代码替代业务逻辑中的判null校验,并且很容易的在出现空指针的时候进行打日志或其他操作. 注:如 ...
- 基于python-django框架的支付宝支付案例
目录 @ 一. 开发前的准备 1. 必须了解的知识 SDK:软件开发工具包,可以为开发者提供快速开发的工具 沙箱环境:也就是测试环境 支付宝支付金额的精度:小数点后两位(面试) 支付宝用的什么加密方式 ...
- 有关Spring事务,看这一篇就足够了
本文将按照声明式事务的五个特性进行介绍: 事务传播机制 事务隔离机制 只读 事务超时 回滚规则 Spring事务传播机制 事务的特性 原子性(Atomicity):事务是一个原子操作,由一系列动作组成 ...
- Junit测试Service类方法教程
Junit测试是很方便的,本博客记录一下Junit测试一些Service接口的方法,这样可以不运行项目,在@Test注解的方法里直接测试 Maven引入jar包: <properties> ...
- Java职责链模式
一.定义 职责链模式,就是将能够处理某类请求事件的一些处理类,类似链条的串联起来.请求在链条上处理的时候,并不知道具体是哪个处理类进行处理的.一定程度上实现了请求和处理的解耦. 实际生活中的经典例子就 ...
- 从CAP到zookeeper和eureka对比
今天看了一篇eureka对比zookeeper的文章,对zookeeper满足CAP中的CP,eureka满足AP产生了一点疑问,故写此篇文章进行一些探讨. 首先我们来看看CAP的定义 Consist ...
- 5分钟了解Prometheus
Prometheus(译:普罗米修斯)用领先的开源监控解决方案为你的指标和警报提供动力(赋能). 1. 概述 1.1. Prometheus是什么? Prometheus是一个开源的系统监控和警报 ...
- commons-beanutils.jar及其支持文件
下载地址: 链接:https://pan.baidu.com/s/1AtiK3nsk0aBuBfMdNwBVGw 密码:6tul
- ORM组件LogORM使用指北
LogORM是一个对数据库进行对象关系映射的ORM组件.当对数据库进行增删改操作时,组件会自动进行日志记录. 该组件支持.Net平台和.NetCore平台,支持SQL Server.Oracle.My ...
- layui table 行按钮事件,启用禁用切换
{{# ){ }} <a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="forbidden& ...