Spring Boot集成Shiro并利用MongoDB做Session存儲(chǔ)的方法詳解
前言
shiro是一個(gè)權(quán)限框架,具體的使用可以查看其官網(wǎng) http://shiro.apache.org/ 它提供了很方便的權(quán)限認(rèn)證和登錄的功能.
而springboot作為一個(gè)開源框架,必然提供了和shiro整合的功能!
之前項(xiàng)目鑒權(quán)一直使用的Shiro,那是在Spring MVC里面使用的比較多,而且都是用XML來配置,用Shiro來做權(quán)限控制相對(duì)比較簡單而且成熟,而且我一直都把Shiro的session放在mongodb中,這個(gè)比較符合mongodb的設(shè)計(jì)初衷,而且在分布式項(xiàng)目中mongodb也作為一個(gè)中間層,用來很好很方便解決分布式環(huán)境下的session同步的問題
自從SpringBoot問世之后我的項(xiàng)目基本上能用SpringBoot的就會(huì)用SpringBoot,用MAVEN做統(tǒng)一集中管理也很方便,雖然SpringBoot也提供了一套權(quán)限安全框架Spring Security,但是相對(duì)來說還是不是太好用,所以還是用Shiro來的方便一點(diǎn),SpringBoot集成Shiro要比Spring MVC要簡單的多,至少?zèng)]有一堆XML配置,看起來更清爽,那么接下來我們就開始集成。
方法如下:
第一步必然是在MAVEN中先添加Shiro和mongo的依賴,我用的Shiro版本是
<shiro.version>1.2.3</shiro.version>
添加依賴:
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>${shiro.version}</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-web</artifactId>
<version>${shiro.version}</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>${shiro.version}</version>
</dependency>
<dependency>
<groupId>org.mongodb</groupId>
<artifactId>mongo-java-driver</artifactId>
<version>3.0.0</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb</artifactId>
<version>1.7.0.RELEASE</version>
</dependency>
然后在application.xml或yml中配置mongodb
spring.data.mongodb.host=127.0.0.1 spring.data.mongodb.port=27017 spring.data.mongodb.database=SHIRO_INFO
配置完成之后我們開始正式寫Shiro認(rèn)證的代碼,先自定義一個(gè)鑒權(quán)realm,繼承自AuthorizingRealm
public class ShiroDbRealm extends AuthorizingRealm {
/**
* 用戶信息操作
*/
private SystemUserService systemUserService;
public ShiroDbRealm() {}
public ShiroDbRealm(SystemUserService systemUserService) {
this.systemUserService = systemUserService;
}
/**
* 授權(quán)信息
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
SimpleAuthorizationInfo info = (SimpleAuthorizationInfo) ShiroKit.getShiroSessionAttr("perms");
if (null != info && !CollectionUtils.isEmpty(info.getRoles())
&& !CollectionUtils.isEmpty(info.getStringPermissions())) {
return info;
}
return null;
}
/**
* 認(rèn)證信息
*/
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken)
throws AuthenticationException {
UsernamePasswordToken token = (UsernamePasswordToken) authcToken;
String userName = token.getUsername();
if (userName != null && !"".equals(userName)) {
SystemUser key = new SystemUser();
key.setLoginName(token.getUsername());
key.setPassword(String.valueOf(token.getPassword()));
SystemUser user = systemUserService.login(key);
if (user != null) {
Subject userTemp = SecurityUtils.getSubject();
userTemp.getSession().setAttribute("userId", user.getId());
userTemp.getSession().setAttribute("userName", user.getUserName());
return new SimpleAuthenticationInfo(user.getLoginName(), user.getPassword(), getName());
}
}
return null;
}
}
存儲(chǔ)session進(jìn)mongodb的Repository和實(shí)現(xiàn):
public interface ShiroSessionRepository {
/**
*
* @param session
*/
void saveSession(Session session);
......
}
MongoDBSessionRepository.java
public class MongoDBSessionRepository implements ShiroSessionRepository {
private MongoTemplate mongoTemplate;
public MongoDBSessionRepository() {}
public MongoDBSessionRepository(MongoTemplate mongoTemplate) {
this.mongoTemplate = mongoTemplate;
}
@Override
public void saveSession(Session session) {
if (session == null || session.getId() == null) {
return;
}
SessionBean bean = new SessionBean();
bean.setKey(getSessionKey(session.getId()));
bean.setValue(SerializeUtil.serialize(session));
bean.setPrincipal(null);
bean.setHost(session.getHost());
bean.setStartTimestamp(session.getStartTimestamp());
bean.setLastAccessTime(session.getLastAccessTime());
bean.setTimeoutTime(getTimeoutTime(session.getStartTimestamp(), session.getTimeout()));
mongoTemplate.insert(bean);
}
......
}
ShiroSessionDAO.java
public class ShiroSessionDAO extends AbstractSessionDAO {
/**
* 日志記錄器
*/
private static final Logger log = LoggerFactory.getLogger(ShiroSessionDAO.class);
/**
* 數(shù)據(jù)庫存儲(chǔ)
*/
private ShiroSessionRepository shiroSessionRepository;
/**
*
* @return
*/
public ShiroSessionRepository getShiroSessionRepository() {
return shiroSessionRepository;
}
/**
*
* @param shiroSessionRepository
*/
public void setShiroSessionRepository(ShiroSessionRepository shiroSessionRepository) {
this.shiroSessionRepository = shiroSessionRepository;
}
@Override
public void update(Session session) throws UnknownSessionException {
getShiroSessionRepository().updateSession(session);
}
@Override
public void delete(Session session) {
if (session == null) {
log.error("session can not be null,delete failed");
return;
}
Serializable id = session.getId();
if (id != null) {
getShiroSessionRepository().deleteSession(id);
}
}
@Override
public Collection<Session> getActiveSessions() {
return getShiroSessionRepository().getAllSessions();
}
@Override
protected Serializable doCreate(Session session) {
Serializable sessionId = this.generateSessionId(session);
this.assignSessionId(session, sessionId);
getShiroSessionRepository().saveSession(session);
return sessionId;
}
@Override
protected Session doReadSession(Serializable sessionId) {
return getShiroSessionRepository().getSession(sessionId);
}
}
OK!所有基礎(chǔ)類已經(jīng)完成,最后寫一個(gè)config用來全部初始化和配置Shiro
@Configuration
public class ShiroConfig {
@Resource
private MongoTemplate mongoTemplate;
@Resource
private SystemUserService systemUserService;// 這是用來判斷用戶名和密碼的service
@Bean
public ShiroFilterFactoryBean shiroFilter(DefaultWebSecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
shiroFilterFactoryBean.setLoginUrl("/login");
shiroFilterFactoryBean.setSuccessUrl("/index");
shiroFilterFactoryBean.setUnauthorizedUrl("/403");
// 攔截器.
Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();
filterChainDefinitionMap.put("/static/**", "anon");
filterChainDefinitionMap.put("/ajaxLogin", "anon");
filterChainDefinitionMap.put("/libs/**", "anon");
filterChainDefinitionMap.put("/images/**", "anon");
filterChainDefinitionMap.put("/logout", "logout");
filterChainDefinitionMap.put("/**", "authc"); shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
return shiroFilterFactoryBean;
}
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(
DefaultWebSecurityManager securityManager) {
AuthorizationAttributeSourceAdvisor adv = new AuthorizationAttributeSourceAdvisor();
adv.setSecurityManager(securityManager);
return adv;
}
@Bean
public DefaultWebSecurityManager securityManager(DefaultWebSessionManager sessionManager,
ShiroDbRealm myShiroRealm) {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
// 設(shè)置realm.
securityManager.setRealm(myShiroRealm);
securityManager.setSessionManager(sessionManager);
return securityManager;
}
/**
* 身份認(rèn)證realm; (這里傳遞systemUserService給自定義的ShiroDbRealm初始化)
*
* @return
*/
@Bean
public ShiroDbRealm myShiroRealm() {
ShiroDbRealm myShiroRealm = new ShiroDbRealm(systemUserService);
return myShiroRealm;
}
@Bean
public DefaultWebSessionManager sessionManager(ShiroSessionDAO shiroSessionDao) {
DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
sessionManager.setGlobalSessionTimeout(1800000l);
sessionManager.setDeleteInvalidSessions(true); sessionManager.setSessionValidationSchedulerEnabled(true);
sessionManager.setSessionDAO(shiroSessionDao);
sessionManager.setSessionIdCookieEnabled(true);
SimpleCookie cookie = new SimpleCookie(ShiroHttpSession.DEFAULT_SESSION_ID_NAME);
cookie.setHttpOnly(true);
cookie.setMaxAge(1800000);
sessionManager.setSessionIdCookie(cookie);
return sessionManager;
}
@Bean
public ShiroSessionDAO shiroSessionDao(MongoDBSessionRepository shiroSessionRepository) {
ShiroSessionDAO dao = new ShiroSessionDAO();
dao.setShiroSessionRepository(shiroSessionRepository);
return dao;
}
@Bean
MongoDBSessionRepository shiroSessionRepository() {
MongoDBSessionRepository resp = new MongoDBSessionRepository(mongoTemplate);
return resp;
}
}
大功告成,這里只是一個(gè)簡單的配置,代碼也是我從項(xiàng)目里面節(jié)選和修改過的,至于在controller里面怎么使用,怎么做不同權(quán)限的鑒權(quán)工作那就在自己的代碼里面實(shí)現(xiàn)就行。
總結(jié)
以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問大家可以留言交流,謝謝大家對(duì)腳本之家的支持。
- Shiro中session超時(shí)頁面跳轉(zhuǎn)的處理方式
- spring boot整合redis實(shí)現(xiàn)shiro的分布式session共享的方法
- spring boot實(shí)戰(zhàn)教程之shiro session過期時(shí)間詳解
- Shiro+Redis實(shí)現(xiàn)登錄次數(shù)凍結(jié)的示例
- springboot整合shiro登錄失敗次數(shù)限制功能的實(shí)現(xiàn)代碼
- SpringBoot+Shiro學(xué)習(xí)之密碼加密和登錄失敗次數(shù)限制示例
- Shiro實(shí)現(xiàn)session限制登錄數(shù)量踢人下線功能
相關(guān)文章
Java深入分析Iterator迭代器與foreach循環(huán)的使用
這篇文章主要介紹了Java-Iterator迭代器與foreach循環(huán),主要包括Iterator迭代器接口的操作方法和foreach?循環(huán)語法解析,需要的朋友可以參考下2022-05-05
Android?Studio中創(chuàng)建java工程的完整步驟
Android?Studio創(chuàng)建java工程是非常麻煩的,因?yàn)锳ndroid?Studio沒有提供直接創(chuàng)建java工程的方法,下面這篇文章主要給大家介紹了關(guān)于Android?Studio中創(chuàng)建java工程的完整步驟,需要的朋友可以參考下2024-01-01
Java獲取此次請(qǐng)求URL以及服務(wù)器根路徑的方法
這篇文章主要介紹了Java獲取此次請(qǐng)求URL以及服務(wù)器根路徑的方法,需要的朋友可以參考下2015-08-08
Springboot中yml對(duì)于list列表配置方式詳解
這篇文章主要介紹了Springboot中yml對(duì)于list列表配置方式詳解,使用@ConfigurationProperties讀取yml配置文件過程中會(huì)遇到讀取yml文件中列表,Config里面使用List集合接收,方法比較簡單,需要的朋友可以參考下2023-11-11
Springmvc工程跳轉(zhuǎn)controller無效的解決
這篇文章主要介紹了Springmvc工程跳轉(zhuǎn)controller無效的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-09-09
JAVA把結(jié)果保留兩位小數(shù)的3種方法舉例
在寫程序的時(shí)候,有時(shí)候可能需要設(shè)置小數(shù)的位數(shù),所以下面這篇文章主要給大家介紹了關(guān)于JAVA把結(jié)果保留兩位小數(shù)的3種方法,文章通過代碼介紹的非常詳細(xì),需要的朋友可以參考下2024-08-08
使用Java的Graphics類進(jìn)行繪圖的方法詳解
這篇文章主要介紹了使用Java的Graphics類進(jìn)行繪圖的方法,是Java的GUI編程的基礎(chǔ),需要的朋友可以參考下2015-10-10
JAVA實(shí)現(xiàn)經(jīng)典掃雷游戲的示例代碼
windows自帶的游戲《掃雷》是陪伴了無數(shù)人的經(jīng)典游戲,本程序參考《掃雷》的規(guī)則進(jìn)行了簡化,用java語言實(shí)現(xiàn),采用了swing技術(shù)進(jìn)行了界面化處理。感興趣的可以學(xué)習(xí)一下2022-01-01
IDEA創(chuàng)建Spring項(xiàng)目無法選擇Java8的問題及解決
文章描述了在使用Spring創(chuàng)建項(xiàng)目時(shí)遇到的問題,通過將服務(wù)器地址從https://start.spring.io/替換為https://start.aliyun.com/,成功解決了無法選擇Java8的問題2025-01-01

