一.是什么镜粤?
Apache Shiro是Java的一個(gè)安全框架捏题。Shiro可以幫助我們完成:認(rèn)證、授權(quán)肉渴、加密公荧、會話管理、與Web集成同规、緩存等循狰。
從外部看:應(yīng)用代碼直接交互的對象是Subject,也就是說Shiro的對外API核心就是Subject券勺,Shiro不提供維護(hù)用戶/權(quán)限绪钥,而是通過Realm讓開發(fā)人員自己注入。
從內(nèi)部看:通過Securty Manage管理外部請求的認(rèn)證認(rèn)證关炼、授權(quán)程腹、加密、會話管理盗扒、緩存等跪楞。對應(yīng)組件是authenticator,Authorizer侣灶,session manager(自定義的sessionDao)甸祭,cache manage
二.框架流程介紹
- 容器的創(chuàng)建:通過EnvironmentLoaderListener監(jiān)聽,在容器啟動時(shí)創(chuàng)建 WebEnvironment 對象褥影,并由該對象來讀取 Shiro 配置文件池户,創(chuàng)建WebSecurityManager 與FilterChainResolver 對象。
- 執(zhí)行攔截器:因?yàn)镾hiro代理了Filter凡怎,先執(zhí)行Shiro的攔截器校焦。ShiroFilter實(shí)現(xiàn)Filter接口的init(),它是整個(gè)程序的入口统倒。(詳細(xì)內(nèi)容見源碼分析)寨典。執(zhí)行完Shiro攔截器后執(zhí)行其他攔截器,之后放行到WebSecurityManager進(jìn)行會話的管理房匆。
- SecurityManager的各組件通過與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)前線程或傳入請求的用戶數(shù)據(jù)的井氢。
-
3.用途:
- 獲取sesion :user .getSession(); (它不需要一個(gè) HTTP 環(huán)境,任何客戶端技術(shù)現(xiàn)在能夠共享會話數(shù)據(jù))
- .對角色和權(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)證組件弦追,通過配置 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ù)對象
Integer userId = Integer.valueOf(principalCollection.toString());//獲取當(dāng)前用戶ID
AuthorityUsers users = this.authorityUsersService.findById(userId);
if (users != null) {
if (users.getAdministrator() == 1) {
//如果是超級管理員,賦予所有權(quán)限
authorizationInfo.addStringPermission("*");
}
}
return authorizationInfo;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
return null;
}
}
2. Authenticator(認(rèn)證器)
- 定義:對用戶的身份驗(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(會話管理器)
- 定義:SessionManager是用來管理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容器的會話遍烦;
* DefaultWebSessionManager:用于Web環(huán)境的實(shí)現(xiàn)俭嘁,可以替代2躺枕,自己維護(hù)著會話,直接廢棄了Servlet容器的會話管理供填。
-
結(jié)構(gòu)圖
- 常用實(shí)現(xiàn)功能
- 監(jiān)聽session狀態(tài)拐云,實(shí)現(xiàn)過程在類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ù)庫中。但如果你不打算實(shí)現(xiàn)你自己的SessionDAO粘捎,那么強(qiáng)烈地建議你為Shiro 的SessionManagerment 啟用EHCache Manager 支持薇缅,將會在內(nèi)存中保存會話。
- 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());
}
//用來統(tǒng)計(jì)當(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)建會話Cookie的模板(參照SimpleCookie)
@Bean
public SessionManager sessionManager(SimpleCookie simpleCookie) {
sessionManager.sessionIdCookie(sessionDAO);
return sessionManager;
}
4.緩存管理器
- CacheManager 實(shí)例會自動地直接傳送到SessionDAO攒磨。然后當(dāng)SessionManager 要求EnterpriseCacheSessionDAO 去持久化一個(gè)Session 時(shí)泳桦,默認(rèn)它使用一個(gè)EHCache 支持的Cache實(shí)現(xiàn)去存儲Session 數(shù)據(jù),若配置其他緩存實(shí)現(xiàn)娩缰,不需配置灸撰,主要是緩存到本地。