好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

SpringBoot中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

查看更多关于SpringBoot中shiro过滤器的重写与配置详解的详细内容...

  阅读:14次