sringboot2+shiro json接口形式未登录时报https中有http请求错误

最近开发一个小项目采用springboot2+shiro前后端分离的方式进行。由于访问使用https证书形式。结果在上线时遇到登录信息过期后shiro设置的跳转接口时重定向为http。从而https访问http报错。网上找了很多都没有一个很好的解决办法。

? ? 一开始想通过redirectHttp10Compatible:解决https环境下使用redirect重定向地址变为http的协议,无法访问服务的问题??? ? ? ? ? ? 设置为false,即关闭了对http1.0协议的兼容支持 ,实际测试不管用。只能从shiro源码进行分析如下:

    Java代码 

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

可以发现他是调用的isAccessAllowed方法和onAccessDenied方法,只要两者有一个可以就可以了,从名字中我们也可以理解,他的逻辑是这样:先调用isAccessAllowed,如果返回的是true,则直接放行执行后面的filter和servlet,如果返回的是false,则继续执行后面的onAccessDenied方法,如果后面返回的是true则也可以有权限继续执行后面的filter和servelt。

只有两个函数都返回false才会阻止后面的filter和servlet的执行。

isAccessAllowed方法在这个类中都是抽象的,依靠实现类实现。onAccessDenied方法不是抽象的,但是调用了另一个抽象的方法:

org.apache.shiro.web.filter.AccessControlFilter.onAccessDenied(ServletRequest, ServletResponse)

这个方法忽略了之前配置的param参数。

这个类中还有其他的属性,比如getLoginUrl,这个很容易猜测,是当没有登录的时候重定向到登录界面的,这个方法就是获得登录界面的位置,默认是/login.jsp,如果我们的登录界面不是这个的话就要重写这个方法。

还有一个特别好使的方法

saveRequestAndRedirectToLogin(ServletRequest, ServletResponse),源码如下:

Java代码
protected void saveRequestAndRedirectToLogin(ServletRequest request, ServletResponse response) throws IOException {
saveRequest(request);
redirectToLogin(request, response);
}

显示保存了当前的request,然后重定向。

源码如下:

Java代码
protected void saveRequest(ServletRequest request) {
WebUtils.saveRequest(request);//关于webutils在别的博客中。
}
protected void redirectToLogin(ServletRequest request, ServletResponse response) throws IOException {
String loginUrl = getLoginUrl();//重定向的界面就是到登录页面。
WebUtils.issueRedirect(request, response, loginUrl); //关于webutils在别的博客中。
}

我们如果在其他类中需要重定向的话就可以直接使用它的WebUtils.issueRedirect(request,response,loginUrl)方法了。
找到办法了只要在onAccessDenied返回未登录状态就好了。

方法一:重写FormAuthenticationFilter
原理:
假设在shiro.xml中配置了 /** = authc,而默认authc对应org.apache.shiro.web.filter.authc.FormAuthenticationFilter过滤器则表示所有路径都被此过滤器拦截。

第一步:新建一个MyFormAuthenticationFilter类extends FormAuthenticationFilter代码如下:

public class MyFormAuthenticationFilter extends FormAuthenticationFilter {

private static final Logger log = LoggerFactory.getLogger(MyFormAuthenticationFilter.class);

@Override
protected boolean onAccessDenied(ServletRequest request,
                                 ServletResponse response) throws IOException {

    HttpServletRequest httpRequest = (HttpServletRequest) request;
    HttpServletResponse httpResponse = (HttpServletResponse) response;

    Subject subject = getSubject(request, response);
    if (subject.getPrincipal() == null) {
        //设置响应头
        httpResponse.setCharacterEncoding("UTF-8");
        httpResponse.setContentType("application/json");
        //设置返回的数据
        ResultMess resultMess = new ResultMess();
        resultMess.setCode(-10000);
        resultMess.setMsg("未登录");
        resultMess.setSuccess(false);
        Gson gson =  new Gson();
        String result = gson.toJson(resultMess);
        //写回给客户端
        PrintWriter out = httpResponse.getWriter();
        out.write(result);
        //刷新和关闭输出流
        out.flush();
        out.close();
    } else {
        //设置响应头
        System.out.println("=========onAccessDenied==========返回json====>>>>");
        httpResponse.setCharacterEncoding("UTF-8");
        httpResponse.setContentType("application/json");
        //设置返回的数据
        ResultMess resultMess = new ResultMess();
        resultMess.setCode(-10000);
        resultMess.setMsg("未登录");
        resultMess.setSuccess(false);
        Gson gson =  new Gson();
        String s = gson.toJson(resultMess);
        //写回给客户端
        PrintWriter out = httpResponse.getWriter();
        out.write(s);
        //刷新和关闭输出流
        out.flush();
        out.close();
    }
    return false;
}

}
第二步:ShiroConfig 类中将重写的MyFormAuthenticationFilter赋予ShiroFilterFactoryBean 代码如下:

@Bean
public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
// 必须设置 SecurityManager
shiroFilterFactoryBean.setSecurityManager(securityManager);
// 如果不设置默认会自动寻找Web工程根目录下的"/login.jsp"页面
// shiroFilterFactoryBean.setLoginUrl("/adminUser/unauth");
// 登录成功后要跳转的链接
shiroFilterFactoryBean.setSuccessUrl("/");
// 未授权界面;
shiroFilterFactoryBean.setUnauthorizedUrl("/adminUser/unauth");
Map<String, Filter> filtersMap = new HashMap<>();
MyFormAuthenticationFilter authFilter = new MyFormAuthenticationFilter();
filtersMap.put("authc", authFilter);
shiroFilterFactoryBean.setFilters(filtersMap);

    // 配置数据库中的resource
    Map<String, String> filterChainDefinitionMap = shiroService.loadFilterChainDefinitions();
    shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
    return shiroFilterFactoryBean;
}

第三步:

将所以的需要拦截的标注为authc,次处的authc和filtersMap.put("authc", authFilter);设置的对应。

这样shiro判断到未登录就进入次拦截器,返回json数据给前端避免了重定向url.

原文地址:https://blog.51cto.com/1745012/2430221

时间: 2024-08-03 01:20:18

sringboot2+shiro json接口形式未登录时报https中有http请求错误的相关文章

Shiro Ajax请求没有权限返回JSON,没有登录返回JSON

本文基于Shiro权限注解方式来控制Controller方法是否能够访问. 例如使用到注解: @RequiresPermissions 来控制是否有对应权限才可以访问 @RequiresUser 来控制是否存在用户登录状态才可以访问 想了解Shiro是如何通过注解来控制权限的,可以查看源码 AopAllianceAnnotationsAuthorizingMethodInterceptor ,其构造方法中添加了几个对应的权限注解方法拦截器(这里不做详细阐述). 用户在请求使用这些注解方式控制的方

vue 判断是否登录,未登录跳转到登录页

网页一进入判断是否登录,未登录跳转到登录页面 router.js export default new Router({ routes: [ { path: '/', name: 'HelloWorld', component: HelloWorld, meta: { title: '首页', requiresAuth: true // 是否需要判断是否登录 } }, { path: '/login', name: 'login', component: login, meta: { title

Django中间件拦截未登录url

1.利用装饰器在视图中拦截未登录的url @login_required(login_url='/user/login/') def homepage(request): pass 这种方法适合于程序中只有少数几个需要登录拦截的url. 2. 利用中间件技术拦截未登录的url 2.1 在settings.py添加MIDDLEWARE设置:middleware.LoginCheckMiddleware MIDDLEWARE = [ 'django.middleware.security.Secur

利用Django中间件middleware解决用户未登录问题(转)

add by zhj: Django的中间件一般用于处理通用性的问题,分为五种,按处理顺序为request_middleware,view_middleware,exception_middleware,template_response_middleware,response_middleware,Django貌似为每种中间件都定义接口,比如request_middleware中间件的接口为process_request(self, request),我们增加新的中间件时,只要实现这些接口就可

vue实现未登录跳转到登录页面

环境:vue 2.9.3; webpack;vue-router 目的:实现未登录跳转 例子:直接在url地址栏输入...../home,但是这个页面要求需要登陆之后才能进入,判断的值就通过登陆之后给本地缓存存入的token判断,如果没有就跳转到登录页面,有的话就打开. 图示: 1.直接在url地址栏输入http://127.0.0.1:9000/#/home,但是页面会直接跳转到登录页,而且会带上参数. --------------------------------------------分

用户未登录或Session超时时重定向到登录页,不那么简单

在网站开发中,我们经常有这样的场景出现: 情景1:对未登录的用户或没有权限的用户,当其想访问某个受限网页时,系统要能够自动转到登录页面.   情景2:对于用session保存用户状态的情况还有这样一种需求,当用户的session已超时时,用户再想执行操作时,也要将其转到登录页面.   在asp.net中,要实现上述的功能容易吗?有人会说:"这太容易了,可以通过下面两种方式实现".   方法一:直接调用asp.net中的response.redirect方法实现 response.red

Python爬虫入门【4】:美空网未登录图片爬取

美空网未登录图片----简介 上一篇写的时间有点长了,接下来继续把美空网的爬虫写完,这套教程中编写的爬虫在实际的工作中可能并不能给你增加多少有价值的技术点,因为它只是一套入门的教程,老鸟你自动绕过就可以了,或者带带我也行. 美空网未登录图片----爬虫分析 首先,我们已经爬取到了N多的用户个人主页,我通过链接拼接获取到了 http://www.moko.cc/post/da39db43246047c79dcaef44c201492d/list.html 在这个页面中,咱们要找几个核心的关键点,发

tp5 _initialize控制器初始化 及 禁止未登录进入和重复登入

首先要建一个公共文件  写一个Base.php 配置文件  当配置了Base 并继承了controller后 其他控制器可直接继承Base 代码如下 下面代码是进入主页 ,同时找到 isLogin方法,通过这个方法去判断是否登录,未登录则强制返回登录页面                                             下面代码是进入登录页面时,同时找到existLogin方法 检测用户之前是否登录,如已登陆过用户,则如下提示,并进入主页面        原文地址:http

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

Post 传值(看不见的传值) Get 传值(看得见的传值) Session - 全局变量组 存放位置:服务端 作用:只要里面有内容,那么这个网站中所有的C#端都能访问到这个变量 -- object类型 格式: web1 后台代码: public partial class _Default : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { Button1.Click += Button1_