经过前面学习 Apache Shiro ,现在结合 Spring Boot 使用在项目里,进行相关配置。
正文
添加依赖
在 pom.xml
文件中添加 shiro-spring
的依赖:
1 | <dependency> |
RBAC
RBAC [1] 是基于角色的访问控制,权限与角色关联,给用户配置相关角色,来获取权限信息。
Shiro 配置
新建一个新的 Shiro
配置类 ShiroConfig
:
1 | package com.wuwii.common.config; |
Filter Chain定义说明:
- 一个URL可以配置多个Filter,使用逗号分隔
- 当设置多个过滤器时,全部验证通过,才视为通过
- 部分过滤器可指定参数,如perms,roles
Shiro内置的FilterChain:
Filter Name | Class |
---|---|
anon | org.apache.shiro.web.filter.authc.AnonymousFilter |
authc | org.apache.shiro.web.filter.authc.FormAuthenticationFilter |
authcBasic | org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter |
perms | org.apache.shiro.web.filter.authz.PermissionsAuthorizationFilter |
port | org.apache.shiro.web.filter.authz.PortFilter |
rest | org.apache.shiro.web.filter.authz.HttpMethodPermissionFilter |
roles | org.apache.shiro.web.filter.authz.RolesAuthorizationFilter |
ssl | org.apache.shiro.web.filter.authz.SslFilter |
user | org.apache.shiro.web.filter.authc.UserFilter |
- anon:所有url都都可以匿名访问
- authc: 需要认证才能进行访问
- user:配置记住我或认证通过可以访问
自定义的拦截器(可选)
如果需要按照自己的需要定义一个 oauth2 的拦截器,则需要 继承AuthenticatingFilter
实现几个方法即可。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
86
87
88
89
90
91
92
93
94
95
96
97/**
* oauth2过滤器
*/
public class OAuth2Filter extends AuthenticatingFilter {
/**
* logger
*/
private static final Logger LOGGER = LoggerFactory.getLogger(OAuth2Filter.class);
protected AuthenticationToken createToken(ServletRequest request, ServletResponse response) throws Exception {
//获取请求token
String token = getRequestToken((HttpServletRequest) request);
if (StringUtils.isBlank(token)) {
return null;
}
return new OAuth2Token(token);
}
/**
* shiro权限拦截核心方法 返回true允许访问resource,
* @param request
* @param response
* @param mappedValue
* @return
*/
protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
return false;
}
/**
* 当访问拒绝时是否已经处理了;
* 如果返回true表示需要继续处理;
* 如果返回false表示该拦截器实例已经处理完成了,将直接返回即可。
* @param request
* @param response
* @return
* @throws Exception
*/
protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
//获取请求token,如果token不存在,直接返回401
String token = getRequestToken((HttpServletRequest) request);
if (StringUtils.isBlank(token)) {
HttpServletResponse httpResponse = (HttpServletResponse) response;
((HttpServletResponse) response).setStatus(401);
response.getWriter().print("没有权限,请联系管理员授权");
return false;
}
return executeLogin(request, response);
}
/**
* 鉴定失败,返回错误信息
* @param token
* @param e
* @param request
* @param response
* @return
*/
protected boolean onLoginFailure(AuthenticationToken token, AuthenticationException e, ServletRequest request, ServletResponse response) {
try {
((HttpServletResponse) response).setStatus(401);
response.getWriter().print("没有权限,请联系管理员授权");
} catch (IOException e1) {
LOGGER.error(e1.getMessage(), e1);
}
return false;
}
/**
* 获取请求的token
*/
private String getRequestToken(HttpServletRequest httpRequest) {
//从header中获取token
String token = httpRequest.getHeader("token");
//如果header中不存在token,则从参数中获取token
if (StringUtils.isBlank(token)) {
return httpRequest.getParameter("token");
}
// 还可以实现从 cookie 获取
Cookie[] cookies = httpRequest.getCookies();
if(null==cookies||cookies.length==0){
return null;
}
for (Cookie cookie : cookies) {
if (cookie.getName().equals("token")) {
token = cookie.getValue();
continue;
}
}
return token;
}
}
具体实现可以参考我的上篇文章 《Apache Shiro的拦截器和认证》
认证实现
Shiro的认证过程最终会交由Realm执行,这时会调用Realm的 getAuthenticationInfo(token)
方法。
该方法主要执行以下操作:
- 检查提交的进行认证的令牌信息
- 根据令牌信息从数据源(通常为数据库)中获取用户信息
- 对用户信息进行匹配验证。
- 验证通过将返回一个封装了用户信息的AuthenticationInfo实例。
- 验证失败则抛出AuthenticationException异常信息。
而在我们的应用程序中要做的就是自定义一个Realm类,继承 AuthorizingRealm
抽象类,重载 doGetAuthenticationInfo ()
,重写获取用户信息的方法。
1 |
|
实现上面两个方法即可完成身份验证和权限验证。
登陆实现
1 | "/login") ( |
权限验证
1 | "用于测试,查询") ( |
简单测试一个例子,sys:user:list1
多加一个 1
肯定会验证失败,查看程序会做什么,它会去我们定义的 Realm 中的 doGetAuthorizationInfo(PrincipalCollection principals)
方法中,执行查询该用户的所有权限。
验证失败后最后程序结果如下:
1 | Caused by: org.apache.shiro.authz.AuthorizationException: Not authorized to invoke method: public org.springframework.http.ResponseEntity com.wuwii.module.sys.controller.SysUserController.query(java.lang.String) |
权限注解
1 |
|
参考资料
- 1.Role-Based Access Control ↩