概述
Shiro是一个功能强大且易于使用的Java安全框架,提供了认证,授权,加密,和会话管理。
shiro的整体架构
Subject:
认证主体,通常包含两个信息。Principals:身份。可以是用户名,邮件,手机号码等等,用来标识一个登录主体身份;
Credentials:凭证。常见有密码,数字证书等等。
在Shiro中可以在.ini文件中指定一个认证主体,也可以从数据库中取。.ini文件的格式如下:
#定义用户
[users]
#用户名 cheng 密码是 123, 角色是 admin
cheng = 123,admin
#定义角色
[roles]
#角色admin对资源user拥有user:delete、update权限
admin = user:delete,user:update
SecurityManager:
Shiro的核心组件。
Authenticator:
认证器,负责主体认证的,这是一个扩展点,如果用户觉得Shiro默认的不好,可以自定义实现;其需要认证策略(Authentication Strategy),即什么情况下算用户认证通过了;
Authorizer:
授权器,或者访问控制器,用来决定主体是否有权限进行相应的操作;即控制着用户能访问应用中的哪些功能;
Realm:
域,Shiro从Realm获取安全数据(如用户、角色、权限)。可以有1个或多个Realm,可以认为是安全实体数据源。
SessionManager:
如果写过Servlet就应该知道Session的概念,Session需要有人去管理它的生命周期,这个组件就是SessionManager;而Shiro并不仅仅可以用在Web环境,也可以用在如普通的JavaSE环境、EJB等环境;所以,Shiro 就抽象了一个自己的Session来管理主体与应用之间交互的数据。
CacheManager:
缓存控制器,来管理如用户、角色、权限等的缓存的;因为这些数据基本上很少去改变,放到缓存中后可以提高访问的性能。
Cryptography:
密码模块,Shiro提高了一些常见的加密组件用于如密码加密/解密的。
SessionDAO:
DAO大家都用过,数据访问对象,用于会话的CRUD,比如我们想把Session保存到数据库,那么可以实现自己的SessionDAO,通过如JDBC写到数据库;比如想把Session放到Memcached中,可以实现自己的Memcached SessionDAO;另外SessionDAO中可以使用Cache进行缓存,以提高性能。
一、shiro的认证过程(Authentication Sequence)
先上图,
如图中所示, 认证过程大致可以分为四步:
Step 1:收集并提交主体(Subject)提交的身份和凭证。用户主体(Subject)发送登录请求, 会把用户信息和凭证信息生成一个AuthenticationToken(身份验证令牌)实例,交由SecurityManager去进一步验证;
Step 2:SecurityManager会把主体传递过来的AuthenticationToken委托认证器Autenticator进行认证;
Step 3:认证器Autenticator首先会去获取realm,即从数据库或者配置文件中得到数据源(所以图中第5步是发生在第3步中的),正确数据和待验证的身份信息数据都准备好了之后,进行真正的认证过程;
Step 4:获取认证策略信息Authentication Stratege,进行认证,认证过程结束。
实际中的开发步骤是跟上述流程是相反的,来看下栗子:
package com.imo.code.shiro;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.realm.text.IniRealm;
import org.apache.shiro.subject.Subject;
import org.junit.Test;
public class IniRealmTest {
//获取realm身份信息数据源
IniRealm iniRealm = new IniRealm("classpath:resources/shiro/user.ini");
@Test
public void testAuthentication() {
//构建shiro核心组件,安全管理器SecurityManager
DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
//绑定SecurityManager的realm
defaultSecurityManager.setRealm(iniRealm);
SecurityUtils.setSecurityManager(defaultSecurityManager);
//生成主体
Subject subject = SecurityUtils.getSubject();
//生成AuthenticationToken实例
UsernamePasswordToken token = new UsernamePasswordToken("cheng", "123");
//提交登录请求
subject.login(token);
System.out.println("============ isAuthenticated: " + subject.isAuthenticated());
//校验角色信息
subject.checkRole("admin");
//校验该用户是否有以下权限
subject.checkPermission("user:delete");
subject.checkPermission("user:update");
}
}