首页 > 开发 > Java > 正文

Spring Boot集成Shiro并利用MongoDB做Session存储的方法详解

2024-07-13 10:14:46
字体:
来源:转载
供稿:网友

前言

shiro是一个权限框架,具体的使用可以查看其官网 http://shiro.apache.org/ 它提供了很方便的权限认证和登录的功能.

而springboot作为一个开源框架,必然提供了和shiro整合的功能!

之前项目鉴权一直使用的Shiro,那是在Spring MVC里面使用的比较多,而且都是用XML来配置,用Shiro来做权限控制相对比较简单而且成熟,而且我一直都把Shiro的session放在mongodb中,这个比较符合mongodb的设计初衷,而且在分布式项目中mongodb也作为一个中间层,用来很好很方便解决分布式环境下的session同步的问题

自从SpringBoot问世之后我的项目基本上能用SpringBoot的就会用SpringBoot,用MAVEN做统一集中管理也很方便,虽然SpringBoot也提供了一套权限安全框架Spring Security,但是相对来说还是不是太好用,所以还是用Shiro来的方便一点,SpringBoot集成Shiro要比Spring MVC要简单的多,至少没有一堆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.1spring.data.mongodb.port=27017spring.data.mongodb.database=SHIRO_INFO

配置完成之后我们开始正式写Shiro认证的代码,先自定义一个鉴权realm,继承自AuthorizingRealm

public class ShiroDbRealm extends AuthorizingRealm { /** * 用户信息操作 */ private SystemUserService systemUserService; public ShiroDbRealm() {} public ShiroDbRealm(SystemUserService systemUserService) { this.systemUserService = systemUserService; } /** * 授权信息 */ @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; } /** * 认证信息 */ 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; }}

存储session进mongodb的Repository和实现:

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); /** * 数据库存储 */ 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!所有基础类已经完成,最后写一个config用来全部初始化和配置Shiro

@Configurationpublic 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(); // 设置realm. securityManager.setRealm(myShiroRealm); securityManager.setSessionManager(sessionManager); return securityManager; } /** * 身份认证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; }}

大功告成,这里只是一个简单的配置,代码也是我从项目里面节选和修改过的,至于在controller里面怎么使用,怎么做不同权限的鉴权工作那就在自己的代码里面实现就行。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对VeVb武林网的支持。


注:相关教程知识阅读请移步到JAVA教程频道。
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表