服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - Java教程 - SpringBoot中shiro过滤器的重写与配置详解

SpringBoot中shiro过滤器的重写与配置详解

2022-11-24 14:28暮晓引流软件 Java教程

在前后端分离跨域访问的项目中shiro进行权限拦截失效 (即使有正确权限的访问也会被拦截) 时造成302重定向错误等问题,为解决这个问题,就需要进行shiro过滤器的重写以及配置。本文详细介绍了解决方法,需要的可以参考一下

问题

遇到问题:在前后端分离跨域访问的项目中shiro进行权限拦截失效 (即使有正确权限的访问也会被拦截) 时造成302重定向错误等问题
报错:Response for preflight is invalid (redirect)

1.302原因:使用ajax访问后端项目时无法识别重定向操作

2.shiro拦截失效原因:跨域访问时有一种带预检访问的跨域,即访问时先发出一条methods为OPTIONS的的访问,这种访问不带cookie等信息。造成shiro误判断为无权限访问。

3.一般使用的访问methods都是:get,post,put,delete

解决方案

1.让shiro不对预检访问拦截

2. 改变shiro中无权限,未登录拦截的重定向,这就需要重写几个过滤器

3. 将重写的过滤器进行配置

实现代码

1.重写shiro 登录 过滤器

过滤器运行机制:

(1)shiro是否拦截访问 以 isAccessAllowed返回值为准

(2)如果isAccessAllowed 方法返回false会进入onAccessDenied方法重定向至 登录 or 无权限 页面

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
package com.yaoxx.base.shiro;
 
import java.io.PrintWriter;
 
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;
import org.apache.shiro.web.util.WebUtils;
import org.springframework.http.HttpStatus;
 
/**
* @version: 1.0
* @since: JDK 1.8.0_91
* @Description:
*       未登录过滤器,重写方法为【跨域的预检访问】放行
 
*/
 
public class MyAuthenticationFilter extends FormAuthenticationFilter {
   
   @Override
   protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
    boolean allowed = super.isAccessAllowed(request, response, mappedValue);
    if (!allowed) {
        // 判断请求是否是options请求
        String method = WebUtils.toHttp(request).getMethod();
        if (StringUtils.equalsIgnoreCase("OPTIONS", method)) {
            return true;
        }
    }
    return allowed;
   }
 
   @Override
   protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
    if (isLoginRequest(request, response)) { // 判断是否登录
        if (isLoginSubmission(request, response)) { // 判断是否为post访问
            return executeLogin(request, response);
        } else {
            // sessionID已经注册,但是并没有使用post方式提交
            return true;
        }
    } else {
        HttpServletRequest req = (HttpServletRequest) request;
        HttpServletResponse resp = (HttpServletResponse) response;
        /*
         * 跨域访问有时会先发起一条不带token,不带cookie的访问。
         * 这就需要我们抓取这条访问,然后给他通过,否则只要是跨域的访问都会因为未登录或缺少权限而被拦截
         * (如果重写了isAccessAllowed,就无需下面的判断)
         */
//          if (req.getMethod().equals(RequestMethod.OPTIONS.name())) {
//              resp.setStatus(HttpStatus.OK.value());
//              return true;
//          }
        /*
         * 跨域的第二次请求就是普通情况的request了,在这对他进行拦截
         */
        String ajaxHeader = req.getHeader(CustomSessionManager.AUTHORIZATION);
        if (StringUtils.isNotBlank(ajaxHeader)) {
            // 前端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");
            resp.setStatus(HttpStatus.UNAUTHORIZED.value());//设置未登录状态码
            PrintWriter out = resp.getWriter();
//              Map<String, String> result = new HashMap<>();
//              result.put("MESSAGE", "未登录用户");
            String result = "{"MESSAGE":"未登录用户"}";
            out.println(result);
            out.flush();
            out.close();
        } else {
            // == 如果是普通访问重定向至shiro配置的登录页面 == //
            saveRequestAndRedirectToLogin(request, response);
        }
    }
    return false;
   }
}

2.重写role权限 过滤器

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
package com.yaoxx.base.shiro;
 
import java.io.IOException;
import java.io.PrintWriter;
 
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.web.filter.authz.RolesAuthorizationFilter;
import org.apache.shiro.web.util.WebUtils;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.RequestMethod;
 
/**
*
* @author: yao_x_x
* @since: JDK 1.8.0_91
* @Description: role的过滤器
*/
 
public class MyAuthorizationFilter extends RolesAuthorizationFilter {
 
   @Override
   public boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue)
        throws IOException {
    boolean allowed =super.isAccessAllowed(request, response, mappedValue);
    if (!allowed) {
        String method = WebUtils.toHttp(request).getMethod();
        if (StringUtils.equalsIgnoreCase("OPTIONS", method)) {
            return true;
        }
    }
    return allowed;
   }
 
   @Override
   protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws IOException {
    HttpServletRequest req = (HttpServletRequest) request;
    HttpServletResponse resp = (HttpServletResponse) response;
    if (req.getMethod().equals(RequestMethod.OPTIONS.name())) {
        resp.setStatus(HttpStatus.OK.value());
        return true;
    }
    // 前端Ajax请求时requestHeader里面带一些参数,用于判断是否是前端的请求
    String ajaxHeader = req.getHeader(CustomSessionManager.AUTHORIZATION);
    if (StringUtils.isNotBlank(ajaxHeader)) {
        // 前端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();
        String result = "{"MESSAGE":"角色,权限不足"}";
        out.println(result);
        out.flush();
        out.close();
        return false;
    }
    return super.onAccessDenied(request, response);
   }
}

3.配置过滤器

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
@Configuration
public class ShiroConfiguration {
    
    @Autowired
    private RoleService roleService;
    @Autowired
    private PermissionService permissionService;
    
    
    
    
    @Bean("shiroFilter")
    public ShiroFilterFactoryBean shiroFilter(@Qualifier("securityManager")SecurityManager manager) {
        ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
        bean.setSecurityManager(manager);
        /* 自定义filter注册 */
        Map<String, Filter> filters = bean.getFilters();
        filters.put("authc", new MyAuthenticationFilter());
        filters.put("roles", new MyAuthorizationFilter());
 
        
        Map<String, String> filterChainDefinitionMap =new LinkedHashMap<>();
        filterChainDefinitionMap.put("/login", "anon");
//      filterChainDefinitionMap.put("/*", "authc");
//      filterChainDefinitionMap.put("/admin", "authc,roles[ADMIN]");
        bean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        
        return bean;
    }

以上就是SpringBoot中shiro过滤器的重写与配置详解的详细内容,更多关于SpringBoot shiro过滤器重写配置的资料请关注服务器之家其它相关文章!

原文链接:https://blog.csdn.net/m0_52789121/article/details/124441941

延伸 · 阅读

精彩推荐