Shiro的体系结构具有三个主要概念-Subject,SecurityManager和Realm。
Subject: “现在在与软件交互的东西”,这个东西可能是你是我,可能是第三方进程。说白了就是穿了马甲的用户类,负责存储与修改当前用户的信息和状态。
之后你会看到,使用 Shiro 实现我们所设计的各种功能,实际上就是在调用 Subject 的 API。
取得主题
import org.apache.shiro.subject.Subject;
import org.apache.shiro.SecurityUtils;
Subject currentUser = SecurityUtils.getSubject();
SecurityManager: Subject 背后的女人,安全相关的操作实际上是由她管理的。只用在项目中配置一次,就可以忘掉她了。
默认的SecurityManager实现是POJO,并且可以使用任何与POJO兼容的配置机制-普通的Java代码,Spring XML,YAML,.properties和.ini文件等进行配置
//加载配置文件,并获取工厂
Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini");
//获取安全管理者实例
SecurityManager sm = factory.getInstance();
//将安全管理者放入全局对象
SecurityUtils.setSecurityManager(sm);
//全局对象通过安全管理者生成Subject对象
Subject subject = SecurityUtils.getSubject();
Realm: 是 Shiro 和安全相关数据(比如用户信息)的桥梁,也就是说,Realm 负责从数据源中获取数据并加工后传给 SecurityManager。
域本质上是特定于安全性的DAO,真正进行用户认证和授权的关键地方
在配置Shiro时,您必须至少指定一个领域用于身份验证和/或授权。可以配置多个Realm,但至少需要一个。
Shiro 为解决下列问题(我喜欢称它们为应用安全的四要素)提供了保护应用的 API:
- 认证 - 用户身份识别,常被称为用户“登录”;
- 授权 - 访问控制;
- 密码加密 - 保护或隐藏数据防止被偷窥;
- 会话管理 - 每用户相关的时间敏感的状态。
(1) Authentication:认证 - 用户身份识别,常被称为用户“登录“
AuthenticationToken token = new UsernamePasswordToken(username, password);
Subject currentUser = SecurityUtils.getSubject();
currentUser.login(token);
(2)Authorization:授权 - 访问控制
1.角色校验
if ( subject.hasRole(“administrator”) ) {
//show the ‘Create User’ button
} else {
//grey-out the button?
}
2.权限校验
if ( subject.isPermitted(“user:create”) ) {
//show the ‘Create User’ button
} else {
//grey-out the button?
}
3.实例级权限校验
if(subject.isPermitted(“ user:delete:jsmith”))){
//删除'jsmith'用户
} else {
//不要删除'jsmith'
}
(3)Session Management 会话管理 - 每用户相关的时间敏感的状态
Session session = subject.getSession();
(4)密码加密 - 保护或隐藏数据防止被偷窥(hash(哈希变换),字节变换)
1.使用JDK的MessageDigest类
try {
MessageDigest md = MessageDigest.getInstance("MD5");
md.digest(bytes);
byte[] hashed = md.digest();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
2.shiro的MD5加密
String hex = new Md5Hash(myFile).toHex();
shiro的SHA-512 hashing and Base64-encoding
String encodedPassword = new Sha512Hash(password, salt, count).toBase64();
3.MD5+盐(一次哈希可能会出现哈希碰撞,虽然MD5不可逆或非对称性,理论上用穷举法可破解)
String password = "123";
String salt = new SecureRandomNumberGenerator().nextBytes().toString();
int times = 2;
String algorithmName = "md5";
String encodedPassword = new SimpleHash(algorithmName,password,salt,times).toString();
System.out.printf("原始密码是 %s , 盐是: %s, 运算次数是: %d, 运算出来的密文是:%s ",password,salt,times,encodedPassword);