一.是什么?
Apache Shiro是Java的一個(gè)安全框架。Shiro可以幫助我們完成:認(rèn)證、授權(quán)、加密、會(huì)話管理、與Web集成、緩存等。
從外部看:應(yīng)用代碼直接交互的對(duì)象是Subject,也就是說(shuō)Shiro的對(duì)外API核心就是Subject,Shiro不提供維護(hù)用戶/權(quán)限,而是通過(guò)Realm讓開發(fā)人員自己注入。
從內(nèi)部看:通過(guò)Securty Manage管理外部請(qǐng)求的認(rèn)證認(rèn)證、授權(quán)、加密、會(huì)話管理、緩存等。對(duì)應(yīng)組件是authenticator,Authorizer,session manager(自定義的sessionDao),cache manage
二.框架流程介紹
- 容器的創(chuàng)建:通過(guò)EnvironmentLoaderListener監(jiān)聽,在容器啟動(dòng)時(shí)創(chuàng)建 WebEnvironment 對(duì)象,并由該對(duì)象來(lái)讀取 Shiro 配置文件,創(chuàng)建WebSecurityManager 與FilterChainResolver 對(duì)象。
- 執(zhí)行攔截器:因?yàn)镾hiro代理了Filter,先執(zhí)行Shiro的攔截器。ShiroFilter實(shí)現(xiàn)Filter接口的init(),它是整個(gè)程序的入口。(詳細(xì)內(nèi)容見源碼分析)。執(zhí)行完Shiro攔截器后執(zhí)行其他攔截器,之后放行到WebSecurityManager進(jìn)行會(huì)話的管理。
- SecurityManager的各組件通過(guò)與subject交互進(jìn)行認(rèn)證,授權(quán)等管理
三.subject介紹**
- 定義:當(dāng)前正與軟件進(jìn)行交互的任何東西,你可以把 Subject 看成是 Shiro 的"User"概念。
- 獲取:Subject user=SecurityUtils.getSubject()(當(dāng)前正在執(zhí)行的 Subject), 它獲取的 Subject 是基于關(guān)聯(lián)了當(dāng)前線程或傳入請(qǐng)求的用戶數(shù)據(jù)的。
-
3.用途:
- 獲取sesion :user .getSession(); (它不需要一個(gè) HTTP 環(huán)境,任何客戶端技術(shù)現(xiàn)在能夠共享會(huì)話數(shù)據(jù))
- .對(duì)角色和權(quán)限的檢查:
- 是否登錄:user.isAuthenticated()
- 是否有特定角色與操作權(quán)限:
user.hasRole("teacher")
user.isPermitted("teacher:save")
user.isPermitted("teacher:save:權(quán)限碼") - 登錄:
- 退出:user.logou()
四.SecurityManager組件介紹
1.Authorizer:
- 定義:操作授權(quán)認(rèn)證組件,通過(guò)配置 Realm 實(shí)現(xiàn)或jsp標(biāo)簽,常用于角色授權(quán)
public class NormalRealm extends AuthorizingRealm{
@Resource
private AuthorityPermissionService permissionService;
@Resource
private AuthorityUsersService authorityUsersService;
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();//創(chuàng)建Shiro權(quán)限數(shù)據(jù)對(duì)象
Integer userId = Integer.valueOf(principalCollection.toString());//獲取當(dāng)前用戶ID
AuthorityUsers users = this.authorityUsersService.findById(userId);
if (users != null) {
if (users.getAdministrator() == 1) {
//如果是超級(jí)管理員,賦予所有權(quán)限
authorizationInfo.addStringPermission("*");
}
}
return authorizationInfo;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
return null;
}
}
2. Authenticator(認(rèn)證器)
- 定義:對(duì)用戶的身份驗(yàn)證(登錄)嘗試負(fù)責(zé)的組件
public class NormalRealm extends AuthorizingRealm {
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
return null;
}
//認(rèn)證
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) token;
Object principal = usernamePasswordToken.getPrincipal();
Object credentials = usernamePasswordToken.getCredentials();
SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(principal, credentials, getName());
return info;
}
}
3. SessionManager(會(huì)話管理器)
- 定義:SessionManager是用來(lái)管理Session的組件,包括:創(chuàng)建,刪除,inactivity(失效)及驗(yàn)證
- Shiro提供了三個(gè)默認(rèn)實(shí)現(xiàn),我們常用DefaultWebSessionManager自定義管理
* DefaultSessionManager:DefaultSecurityManager使用的默認(rèn)實(shí)現(xiàn),用于JavaSE環(huán)境;
* ServletContainerSessionManager:用于Web環(huán)境,其直接使用Servlet容器的會(huì)話;
* DefaultWebSessionManager:用于Web環(huán)境的實(shí)現(xiàn),可以替代2,自己維護(hù)著會(huì)話,直接廢棄了Servlet容器的會(huì)話管理。
-
結(jié)構(gòu)圖
image.png - 常用實(shí)現(xiàn)功能
- 監(jiān)聽session狀態(tài),實(shí)現(xiàn)過(guò)程在類4中
public class sessionLister implements SessionListener {
@Override
public void onStart(Session session) {
}
@Override
public void onStop(Session session) {
}
@Override
public void onExpiration(Session session) {
}
}
@Bean
public SessionManager sessionManager(RedisSessionDAO sessionDAO) {
sessionManager.setSessionListeners( new sessionLister() );
return sessionManager;
}
- Session持久化,自定義sessionDAO組件
sessionDAO:屬性sessionDAO,自定義SessionDAO實(shí)現(xiàn)AbstractSessionDAO,包含增刪改查方便,可以將session持久化到redis,數(shù)據(jù)庫(kù)中。但如果你不打算實(shí)現(xiàn)你自己的SessionDAO,那么強(qiáng)烈地建議你為Shiro 的SessionManagerment 啟用EHCache Manager 支持,將會(huì)在內(nèi)存中保存會(huì)話。
- Session持久化,自定義sessionDAO組件
@Component
public class RedisSessionDAO extends AbstractSessionDAO {
@Resource(name = "redisTemplate")
private ValueOperations<Serializable, Session> valueOperations;
@Override
public void update(Session session) throws UnknownSessionException {
this.saveSession(session);
}
@Override
public void delete(Session session) {
if (session == null || session.getId() == null) {
logger.error("session or session id is null");
return;
}
valueOperations.getOperations().delete(session.getId());
}
//用來(lái)統(tǒng)計(jì)當(dāng)前活動(dòng)的session
@Override
public Collection<Session> getActiveSessions() {
return sessions;
}
@Override
protected Serializable doCreate(Session session) {
return sessionId;
}
@Override
protected Session doReadSession(Serializable sessionId) {
return s;
}
}
@Bean
public SessionManager sessionManager(RedisSessionDAO sessionDAO) {
sessionManager.setSessionDAO(sessionDAO);
return sessionManager;
}
- 創(chuàng)建會(huì)話Cookie的模板(參照SimpleCookie)
@Bean
public SessionManager sessionManager(SimpleCookie simpleCookie) {
sessionManager.sessionIdCookie(sessionDAO);
return sessionManager;
}
4.緩存管理器
- CacheManager 實(shí)例會(huì)自動(dòng)地直接傳送到SessionDAO。然后當(dāng)SessionManager 要求EnterpriseCacheSessionDAO 去持久化一個(gè)Session 時(shí),默認(rèn)它使用一個(gè)EHCache 支持的Cache實(shí)現(xiàn)去存儲(chǔ)Session 數(shù)據(jù),若配置其他緩存實(shí)現(xiàn),不需配置,主要是緩存到本地。