授权
授权方式
编程式
1
2
3
4
5
6Subject subject = SecurityUtils.getSubject();
if(subject.hasRole("admin")){
//有权限
}else{
//无权限
}注解式
1
2
3
4"admin") (
public void hello(){
//有权限
}标签式
1
2
3
4
5JSP/GSP 标签:在JSP/GSP 页面通过相应的标签完成:
<shiro:hasRole name="admin">
<!-- 有权限 -->
</shiro:hasRole>
注意:Thymeleaf 中使用shiro需要额外集成!
授权实现
首先模拟一下假数据,不操作数据库
在CustomerRealm下有一个doGetAuthorizationInfo方法
这里就负责授权的操作
现在就假设普通用户能看到用户管理 admin可以看到所有的菜单
标签式:
shiro标签引入1
<%@taglib prefix="shiro" uri="http://shiro.apache.org/tags"%>
在index.jsp添加上shiro标签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<ul>
<shiro:hasAnyRoles name="user,admin">
<li><a href="">用户管理</a>
<ul>
<shiro:hasPermission name="user:add:*">
<li><a href="">添加</a></li>
</shiro:hasPermission>
<shiro:hasPermission name="user:delete:*">
<li><a href="">删除</a></li>
</shiro:hasPermission>
<shiro:hasPermission name="user:update:*">
<li><a href="">修改</a></li>
</shiro:hasPermission>
<shiro:hasPermission name="user:find:*">
<li><a href="">查询</a></li>
</shiro:hasPermission>
</ul>
</li>
</shiro:hasAnyRoles>
<shiro:hasRole name="admin">
<li><a href="">商品管理</a></li>
<li><a href="">订单管理</a></li>
<li><a href="">物流管理</a></li>
</shiro:hasRole>
</ul>
CustomerRealm中写上对应的授权方法1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
//获取身份信息
String primaryPrincipal = (String) principalCollection.getPrimaryPrincipal();
System.out.println("调用授权验证:"+primaryPrincipal);
//根据主身份信息获取角色和权限信息
if("xiaochen".equals(primaryPrincipal)){
SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
simpleAuthorizationInfo.addRole("user");
simpleAuthorizationInfo.addStringPermission("user:find:*");
simpleAuthorizationInfo.addStringPermission("user:update:*");
return simpleAuthorizationInfo;
}
return null;
}
现在xiaochen这个账号就是个普通用户 可以看到用户管理 并且对所有文件都具有修改和查找的操作权力 他只能看见修改和查找的功能 看到不添加删除功能
这就完成了通过标签的方式完成了授权的操作,实际开发中一般不会使用这种方式去完成授权操作
代码式:
创建一个OrderController1
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
27package com.ceit.springboot_jsp_shiro.controller;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
public class OrderController {
public String save(){
//获取主体对象
Subject subject = SecurityUtils.getSubject();
//代码方式
if (subject.hasRole("admin")) {
System.out.println("保存订单");
}else{
System.out.println("无权访问");
}
//基于权限字符串
return "redirect:/index.jsp";
}
}
这是个简单的演示 如果xiaochen是admin 那就控制台输出保存订单
注解式:
将上面的代码添加上一个注解即可1
2@RequestMapping("save")
@RequiresRoles("admin")//用来判断角色
如果要判断多个角色1
//用来判断角色 同时具有admin和user身份
还有判断权限字符串的注解1
//用来判断权限字符串
授权数据持久化
角色信息获取
首先要完成通过数据库授权的操作,自然是先要去设计一下库表了
这里就不讲过程了 直接贴sql文件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/*
Navicat MySQL Data Transfer
Source Server : localhost
Source Server Version : 80020
Source Host : localhost:3306
Source Database : shiro_spring
Target Server Type : MYSQL
Target Server Version : 80020
File Encoding : 65001
Date: 2020-12-07 17:40:29
*/
SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- Table structure for t_pers
-- ----------------------------
DROP TABLE IF EXISTS `t_pers`;
CREATE TABLE `t_pers` (
`id` int NOT NULL AUTO_INCREMENT,
`name` varchar(80) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL,
`url` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- ----------------------------
-- Table structure for t_role
-- ----------------------------
DROP TABLE IF EXISTS `t_role`;
CREATE TABLE `t_role` (
`id` int NOT NULL AUTO_INCREMENT,
`name` varchar(60) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- ----------------------------
-- Table structure for t_role_perms
-- ----------------------------
DROP TABLE IF EXISTS `t_role_perms`;
CREATE TABLE `t_role_perms` (
`id` int NOT NULL,
`roleid` int DEFAULT NULL,
`permsid` int DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- ----------------------------
-- Table structure for t_user
-- ----------------------------
DROP TABLE IF EXISTS `t_user`;
CREATE TABLE `t_user` (
`id` int NOT NULL AUTO_INCREMENT,
`username` varchar(255) DEFAULT NULL,
`password` varchar(255) DEFAULT NULL,
`salt` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Table structure for t_user_role
-- ----------------------------
DROP TABLE IF EXISTS `t_user_role`;
CREATE TABLE `t_user_role` (
`id` int NOT NULL,
`userid` int DEFAULT NULL,
`roleid` int DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
t_role表内容:
id | name |
---|---|
1 | admin |
2 | user |
3 | product |
t_user_role表内容:
id | userid | roleid |
---|---|---|
1 | 1 | 1 |
2 | 2 | 2 |
3 | 2 | 3 |
接着就是构建实体类Perms 和 Role
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
31package com.ceit.springboot_jsp_shiro.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
@Data
@Accessors(chain = true)
@AllArgsConstructor
@NoArgsConstructor
public class Role {
private String id;
private String name;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Perms: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
40package com.ceit.springboot_jsp_shiro.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
@Data
@Accessors(chain = true)
@AllArgsConstructor
@NoArgsConstructor
public class Perms {
private String id;
private String name;
private String url;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
}
User实体类中也应该添加上一个roles1
2
3
4
5
6
7
8
9
10//定义角色集合
private List<Role> roles;
public List<Role> getRoles() {
return roles;
}
public void setRoles(List<Role> roles) {
this.roles = roles;
}
UserDAO中开发一个查询方法1
2//根据用户名查询所有角色
User findRolesByUserName(String username);
对应的Service一样1
2//根据用户名查询所有角色
User findRolesByUserName(String username);
接着在UserDAOMapper.xml中添加select方法1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19<resultMap id="userMap" type="User">
<id column="uid" property="id" />
<result column="username" property="username" />
<!-- 角色信息-->
<collection property="roles" javaType="list" ofType="Role">
<id column="id" property="id" />
<result column="rname" property="name" />
</collection>
</resultMap>
<select id="findRolesByUserName" parameterType="String" resultMap="userMap">
select u.id uid,u.username,r.id,r.name rname
from t_user u
left join t_user_role ur
on u.id=ur.userid
left join t_role r
on ur.roleid=r.id
where u.username=#{username};
</select>
接下来就是业务层的实现了1
2
3
4
public User findRolesByUserName(String username) {
return userDAO.findRolesByUserName(username);
}
都做好了 就可以回到我们的自定义Realm了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 @Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
//获取身份信息
String primaryPrincipal = (String) principalCollection.getPrimaryPrincipal();
System.out.println("调用授权验证:"+primaryPrincipal);
//根据主身份信息获取角色和权限信息
// if("xiaochen".equals(primaryPrincipal)){
// SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
//
// simpleAuthorizationInfo.addRole("user");
//
// simpleAuthorizationInfo.addStringPermission("user:find:*");
// simpleAuthorizationInfo.addStringPermission("user:update:*");
//
// return simpleAuthorizationInfo;
// }
UserService userService = (UserService) ApplicationContextUtils.getBean("userService");
User user = userService.findRolesByUserName(primaryPrincipal);
//授权角色信息
if(!CollectionUtils.isEmpty(user.getRoles())){
SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
user.getRoles().forEach(role ->{
simpleAuthorizationInfo.addRole(role.getName());
});
return simpleAuthorizationInfo;
}
return null;
}
这样就完成了从写死数据到连接数据库的授权操作了
权限信息获取
获取权限信息在数据库就比较麻烦了 因为我们既需要查到他的角色信息还要查到他的权限信息
现在需要定义一个权限集合 但权限是绑定角色的 所以就需要在Role实体类中定义一个权限的集合1
2//定义权限集合
private List<Perms> perms;
UserDAO中也添加上方法1
2//根据角色id查询权限集合的方法
List<Perms> findPermsByRoleId(String id);
Service也加上1
2//根据角色id查询权限集合的方法
List<Perms> findPermsByRoleId(String id);
Servicelmpl业务层实现一下1
2
3
4
public List<Perms> findPermsByRoleId(String id) {
return userDAO.findPermsByRoleId(id);
}
对应的Mapper添加上select1
2
3
4
5
6
7
8
9<select id="findPermsByRoleId" parameterType="String" resultType="Perms">
select p.id,p.name,p.url,r.name
from t_role r
left join t_role_perms rp
on r.id = rp.roleid
left join t_perms p
on rp.permsid = p.id
where r.id=#{id};
</select>
这些都做完了 就可以去自定义Realm中添加获取权限信息了
1 | @Override |
这样,以数据库的认证授权操作就全部做完了
剩下的就是去优化了 因为现在这样写 每次登录的时候都会去查数据库 所以我们要将授权角色信息和权限信息进行一个缓存 来优化我们的认证和授权