参考:https://jinnianshilongnian.iteye.com/blog/2018936
1.架构原理图
Shiro的核心部分是SecurityManager,它负责安全认证与授权。Shiro本身已经实现了所有的细节,用户可以完全把它当做一个黑盒来使用。SecurityUtils对象,本质上就是一个工厂类似Spring中的ApplicationContext。Subject是初学者比较难于理解的对象,很多人以为它可以等同于User,其实不然。Subject中文翻译:项目,而正确的理解也恰恰如此。它是你目前所设计的需要通过Shiro保护的项目的一个抽象概念。通过令牌(token)与项目(subject)的登陆(login)关系,Shiro保证了项目整体的安全。
2.Shiro中的AuthenticationInfo,AuthorizationInfo
AuthenticationInfo代表了用户的角色信息集合,AuthorizationInfo代表了角色的权限信息集合。
Authentication:身份认证/登录,验证用户是不是拥有相应的身份;
Authorization:授权,即权限验证,验证某个已认证的用户是否拥有某个权限;即判断用户是否能做事情,常见的如:验证某个用户是否拥有某个角色。或者细粒度的验证某个用户对某个资源是否具有某个权限;
当设计人员对项目中的某一个url路径设置了只允许某个角色或具有某种权限才可以访问的控制约束的时候,Shiro就可以通过以上两个对象来判断。
3.实现Realm
Realm:域,Shiro从从Realm获取安全数据(如用户、角色、权限),就是说SecurityManager要验证用户身份,那么它需要从Realm获取相应的用户进行比较以确定用户身份是否合法;也需要从Realm得到用户相应的角色/权限进行验证用户是否能进行操作;可以把Realm看成DataSource,即安全数据源。
也就是说对于我们而言,最简单的一个Shiro应用:
a、应用代码通过Subject来进行认证和授权,而Subject又委托给SecurityManager;
b、我们需要给Shiro的SecurityManager注入Realm,从而让SecurityManager能得到合法的用户及其权限进行判断。
需要了解:缓存机制、散列算法、加密算法
(1)缓存机制
Ehcache是很多Java项目中使用的缓存框架,Hibernate就是其中之一。它的本质就是将原本只能存储在内存中的数据通过算法保存到硬盘上,再根据需求依次取出。可以把Ehcache理解为一个Map<String,Object>对象,通过put保存对象,再通过get取回对象。
(2)散列算法与加密算法
md5是本文会使用的散列算法,加密算法本文不会涉及。散列和加密本质上都是将一个Object变成一串无意义的字符串,不同点是经过散列的对象无法复原,是一个单向的过程。例如,对密码的加密通常就是使用散列算法,因此用户如果忘记密码只能通过修改而无法获取原始密码。但是对于信息的加密则是正规的加密算法,经过加密的信息是可以通过秘钥解密和还原。
(3)用户注册
请注意,虽然我们一直在谈论用户登录的安全性问题,但是说到用户登录首先就是用户注册。如何保证用户注册的信息不丢失,不泄密也是项目设计的重点。
public class PasswordHelper {
private RandomNumberGenerator randomNumberGenerator = new SecureRandomNumberGenerator();
private String algorithmName = "md5";
private final int hashIterations = 2;
public void encryptPassword(User user) {
// User对象包含最基本的字段Username和Password
user.setSalt(randomNumberGenerator.nextBytes().toHex());
// 将用户的注册密码经过散列算法替换成一个不可逆的新密码保存进数据,散列过程使用了盐
String newPassword = new SimpleHash(algorithmName, user.getPassword(),
ByteSource.Util.bytes(user.getCredentialsSalt()), hashIterations).toHex();
user.setPassword(newPassword);
}
}
如果不清楚什么叫加盐可以忽略散列的过程,只要明白存储在数据库中的密码是根据户注册时填写的密码所产生的一个新字符串就可以了。经过散列后的密码替换用户注册时的密码,然后将User保存进数据库。剩下的工作就丢给UserService来处理。
那么这样就带来了一个新问题,既然散列算法是无法复原的,当用户登录的时候使用当初注册时的密码,我们又应该如何判断?答案就是需要对用户密码再次以相同的算法散列运算一次,再同数据库中保存的字符串比较。
(4)匹配
CredentialsMatcher是一个接口,功能就是用来匹配用户登录使用的令牌和数据库中保存的用户信息