Springboot+shiro无权限跳转失败


使用shiro完成了登录验证以及权限的验证,当用户无权限的时候是需要跳转到403也没用,但是我这设置还是没有作用,最终经过排查以及百度加上查看源码解决问题,本篇文章做一个记录。

发现问题

在shiro做权限管理的过程中,用户无权限的时候,是需要跳转到403.html页面的,我在setUnauthorizedUrl也配置的403的跳转了。
但是在实际跳转中死活无法跳转出现如图的问题
01.jpg

Not authorized to invoke method:未授权调用方法。
但是我也设置了未授权界面跳转了啊

那么大概率的问题出现在了setUnauthorizedUrl这个方法上面了,
点击这个方法之后,setUnauthorizedUrl方法就只有赋值

1
2
3
public void setUnauthorizedUrl(String unauthorizedUrl) {
this.unauthorizedUrl = unauthorizedUrl;
}

unauthorizedUrl这个参数是用来干嘛的,通过查找之后除了在setUnauthorizedUrl()这个方法中出现
还出现在了applyUnauthorizedUrlIfNecessary()这个方法中了

1
2
3
4
5
6
7
8
9
10
11
private void applyUnauthorizedUrlIfNecessary(Filter filter) {
String unauthorizedUrl = this.getUnauthorizedUrl();
if (StringUtils.hasText(unauthorizedUrl) && filter instanceof AuthorizationFilter) {
AuthorizationFilter authzFilter = (AuthorizationFilter)filter;
String existingUnauthorizedUrl = authzFilter.getUnauthorizedUrl();
if (existingUnauthorizedUrl == null) {
authzFilter.setUnauthorizedUrl(unauthorizedUrl);
}
}

}

通过对源码的一步步追踪,发现在配置配置全局属性applyGlobalPropertiesIfNecessary的方法中会调用applyUnauthorizedUrlIfNecessary方法

1
2
3
4
5
6
//配置全局属性,只要是针对特定类型的Filter配置其所需要的URL属性
private void applyGlobalPropertiesIfNecessary(Filter filter) {
applyLoginUrlIfNecessary(filter);
applySuccessUrlIfNecessary(filter);
applyUnauthorizedUrlIfNecessary(filter);
}

其他的暂时就不解释了

分析

在applyUnauthorizedUrlIfNecessary方法中有有一个判断,if (StringUtils.hasText(unauthorizedUrl) && filter instanceof AuthorizationFilter)
其中filter必须为AuthorizationFilter类型的过滤器才可以,但是什么类型的过滤器才算是AuthorizationFilter类型的呢,
点击AuthorizationFilter,进入正抽象类中查看它的正常类,得到如图所示

03.jpg

那么红圈中的这些过滤器到底是什么呢?

在配置shiro 过滤器的管理的时候会实例化ShiroFilterFactoryBean对象
同对代码的跟踪找到createFilterChainManager这个方法,这个方法是创建过滤器

1
DefaultFilterChainManager manager = new DefaultFilterChainManager();

会将所有默认的过滤器获取到
通过对DefaultFilterChainManager类的代码跟踪

1
2
3
4
5
6
7
8
9
10
11
  //添加默认的过滤器
protected void addDefaultFilters(boolean init) {
DefaultFilter[] var2 = DefaultFilter.values();
int var3 = var2.length;

for(int var4 = 0; var4 < var3; ++var4) {
DefaultFilter defaultFilter = var2[var4];
this.addFilter(defaultFilter.name(), defaultFilter.newInstance(), init, false);
}

}

DefaultFilter枚举

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
public enum DefaultFilter {
anon(AnonymousFilter.class),
authc(FormAuthenticationFilter.class),
authcBasic(BasicHttpAuthenticationFilter.class),
logout(LogoutFilter.class),
noSessionCreation(NoSessionCreationFilter.class),
perms(PermissionsAuthorizationFilter.class),
port(PortFilter.class),
rest(HttpMethodPermissionFilter.class),
roles(RolesAuthorizationFilter.class),
ssl(SslFilter.class),
user(UserFilter.class);

private final Class<? extends Filter> filterClass;

private DefaultFilter(Class<? extends Filter> filterClass) {
this.filterClass = filterClass;
}

public Filter newInstance() {
return (Filter)ClassUtils.newInstance(this.filterClass);
}

public Class<? extends Filter> getFilterClass() {
return this.filterClass;
}

public static Map<String, Filter> createInstanceMap(FilterConfig config) {
Map<String, Filter> filters = new LinkedHashMap(values().length);
DefaultFilter[] var2 = values();
int var3 = var2.length;

for(int var4 = 0; var4 < var3; ++var4) {
DefaultFilter defaultFilter = var2[var4];
Filter filter = defaultFilter.newInstance();
if (config != null) {
try {
filter.init(config);
} catch (ServletException var9) {
String msg = "Unable to correctly init default filter instance of type " + filter.getClass().getName();
throw new IllegalStateException(msg, var9);
}
}

filters.put(defaultFilter.name(), filter);
}

return filters;
}
}

现在知道在抽象类AuthorizationFilter中红圈的具体类的来源了。
通过对DefaultFilter和AuthorizationFilter的观察得知
属于AuthorizationFilter类型的过滤类

  1. roles(RolesAuthorizationFilter.class),
  2. perms(PermissionsAuthorizationFilter.class),
  3. rest(HttpMethodPermissionFilter.class),
  4. ssl(SslFilter.class),
    unauthorizedUrl会生效。

属于AuthenticationFilter类型的过滤器

  1. anon(AnonymousFilter.class),
  2. authc(FormAuthenticationFilter.class),
  3. authcBasic(BasicHttpAuthenticationFilter.class),
  4. logout(LogoutFilter.class),
    unauthorizedUrl不会生效。

    解决

    现在不跳转的问题找到了,得找解决的办法。
    1.对抛出未授权异常UnauthorizedException进行处理
    2.把为AuthenticationFilter过滤器改为AuthorizationFilter过滤器

方法的处理:

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
/**
* 全局异常处理类
*
*/
@ControllerAdvice
@Order(-1)
public class ExceptionHandler {

private final Logger logger = LoggerFactory.getLogger(ExceptionHandler.class);

/**
* 无权访问该资源异常
*/
@org.springframework.web.bind.annotation.ExceptionHandler(UnauthorizedException.class)
@ResponseStatus(HttpStatus.UNAUTHORIZED)
public String unAuth(HttpServletRequest request, UnauthorizedException e) {
return "/error/403.html";
}

/**
* 拦截未知的运行时异常
*
* @return
*/
@org.springframework.web.bind.annotation.ExceptionHandler(RuntimeException.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public String errorHtml500(HttpServletRequest request, Exception exception) {
return "/error/500.html";
}
}

注解的解释:

@ControllerAdvice:异常处理器应用到所有控制器。
@Order(-1):定义组件的加载顺序。值越小拥有越高的优先级。

总结

参考链接:

https://www.iteye.com/blog/jinnianshilongnian-1866350
https://blog.csdn.net/ljz2016/article/details/81214184
https://www.jianshu.com/p/e03f5b54838c

-------------本文结束感谢您的阅读-------------