Shiro学习一

2018年还没毕业时写的blog

Posted by MatthewHan on 2019-07-12

前言

新的公司让我去熟悉下Shiro框架,公司的项目的权限管理都是基于Shiro写的,照着前辈们的blog学习了一番,这里做点个人学习记录。

Shiro的整体架构图

Shiro架构图

</div>

首先是Shiro的几个组件

  • SecurityManager
    即所有Subject的管理者,这是Shiro框架的核心组件,可以把他看做是一个Shiro框架的全局管理组件,用于调度各种Shiro框架的服务。
  • Authenticator
    认证器,登入登出,对“Who are you?”进行核实。通常涉及用户名和密码。
  • Authorizer
    授权器,赋予主体有哪些权限,身份验证通过后,由这个组件对登录人员进行访问控制的筛查,比如“who can do what”, 或者“who can do which actions”。Shiro 采用“基于 Realm”的方法,即用户(又称 Subject)、用户组、角色和 permission 的聚合体。
  • Session Manager
    这个组件保证了异构客户端的访问,配置简单。它是基于POJO/J2SE的,不跟任何的客户端或者协议绑定。
  • Subject
    即当前用户,在权限管理的应用程序里往往需要知道谁能够操作什么,谁拥有操作该程序的权利,shiro中则需要通过Subject来提供基础的当前用户信息,Subject 不仅仅代表某个用户,也可以是第三方进程、后台帐户(Daemon Account)或其他类似事物。
  • Realms
    Realms也就是域,是用户的信息认证器和用户的权限人证器,我们需要自己来实现Realms来自定义的管理我们自己系统内部的权限规则。

通过ini文件来自定义Realm

Maven依赖

1
2
3
4
5
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.2.3</version>
</dependency>

shiro.ini

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
# -----------------------------------------------------------------------------
# Users and their (optional) assigned roles
# username = password, role1, role2, ..., roleN
# -----------------------------------------------------------------------------
[users]

#用户名(登陆账号)是root,密码是123,角色是admin管理员

root = 123,admin
user001 = 123,productManager
user002 = 123,orderManager

# -----------------------------------------------------------------------------
# Roles with assigned permissions
# roleName = perm1, perm2, ..., permN
# -----------------------------------------------------------------------------
[roles]

#admin管理员权限拉满,什么都能做
admin = *

#产品经理只能做产品的管理
productManager = addProduct,deleteProduct,editProduct,listProduct

#订单管理员只能做订单的管理
orderManager = addOrder,deleteOrder,editOrder,listOrder

这里分配了三种角色各自拥有不同的权限

  • admin

    • 拥有所有权限
  • productManager

    • addProduct
    • deleteProduct
    • editProduct
    • listProduct
  • orderManager
    • addOrder
    • deleteOrder
    • editOrder
    • listOrder

Tutorial .java

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
98
99
100
101
102
103
104
105
package shiro;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.Factory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* Created by MatthewHan on 2018.
*/
public class Tutorial {

private static final transient Logger log = LoggerFactory.getLogger(Tutorial.class);
public static void main(String[] args) {

//step1.使用了IniSecurityManagerFactory类读取ini文件
Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini");

//step2.解析ini文件,返回一个Securitymanager对象,对象含有配置信息
SecurityManager securityManager = factory.getInstance();

//step3.
SecurityUtils.setSecurityManager(securityManager);


//获取当前使用的用户
Subject currentUser = SecurityUtils.getSubject();
//获取Session信息
Session session = currentUser.getSession();
session.setAttribute("oneKey","aValue");
String value = (String)session.getAttribute("oneKey");
if(value.equals("trueValue"))
{
log.info("值正确!["+ value +"]");
}
else
{
log.info("value有错误哦!您的value:["+ value+"]");
}

log.info("\n**********************是否登陆成功*********************\n");

//登陆后的当前用户,这样我们就可以检查角色和权限:
if(!currentUser.isAuthenticated()) {
String username = "user001", password = "1123";
UsernamePasswordToken token = new UsernamePasswordToken(username, password);
token.setRememberMe(true);

try {
currentUser.login(token);//登陆
log.info("你居然登陆上了,牛逼");
log.info("\n**********************打印这些登陆用户的信息*********************\n");

//打印这些登陆用户的信息
log.info("用户[" + currentUser.getPrincipal() + "] 登陆成功!");

//测试一个role
String roleName = "productManager";
if (currentUser.hasRole(roleName)) {
log.info("这个角色:[" + roleName + "]");
} else {

log.info("emmmm,mere mortal!");
}
log.info("\n**********************测试不同类型的权限*********************\n");

//测试不同类型的权限
if (currentUser.isPermitted("addProduct")) {
log.info("您可以对产品进行管理");
} else {
log.info("你不配使用");
}

//part2
if (currentUser.isPermitted("addOrder")) {
log.info("您可以对订单系统进行管理");
}
else{
log.info("抱歉,你不配管理订单系统");
}


} catch (UnknownAccountException uae) {
log.info("没有这个用户名:" + token.getPrincipal());
} catch (IncorrectCredentialsException ice) {
log.info("这个账号" + token.getPrincipal() + "的密码是错的啦,try again?");
} catch (LockedAccountException lae) {
log.info("这个用户" + token.getPrincipal() + "已被封锁" + "请联系管理员解锁");
} catch (AuthenticationException ae) {
log.info("发生了一些未知的情况,请联系管理员!");
}

}

//用户登出
currentUser.logout();
System.exit(0);

}
}

测试类Tutorial,通过UsernamePasswordToken创建的token对象来让Subject(当前对象)进行登陆验证,认证通过后,可以用getPrincipal()这个方法来获取当前对象的用户名.

角色相关验证方法

Subject方法 描述
hasRole(String roleName) 当用户拥有指定角色时,返回true
hasRoles(List roleNames) 按照列表顺序返回相应的一个boolean值数组
hasAllRoles(Collection roleNames) 如果用户拥有所有指定角色时,返回true

</br>

Subject方法 描述
checkRole(String roleName) 断言用户是否拥有指定角色
checkRoles(Collection roleNames) 断言用户是否拥有所有指定角色
checkRoles(String… roleNames) 对上一方法的方法重载

权限相关验证方法

Subject方法 说明
checkPermission(Permission p) 断言用户是否拥有制定权限
checkPermission(String perm) 断言用户是否拥有制定权限
checkPermissions(Collection perms) 断言用户是否拥有所有指定权限
checkPermissions(String… perms) 断言用户是否拥有所有指定权限

</br>

Subject方法 描述
isPermitted(Permission p) Subject拥有制定权限时,返回true
isPermitted(List perms) 返回对应权限的boolean数组
isPermittedAll(Collection perms) Subject拥有所有制定权限时,返回true