SpringBoot集成Shiro并用MongoDB做Session存储

本文涉及的产品
云数据库 MongoDB,独享型 2核8GB
推荐场景:
构建全方位客户视图
简介: 之前项目鉴权一直使用的Shiro,那是在Spring MVC里面使用的比较多,而且都是用XML来配置,用Shiro来做权限控制相对比较简单而且成熟,而且我一直都把Shiro的session放在mongodb中,这个比较符合mongodb的设计初衷,而且在分布式项目中mongodb也作为一个中间层,用来很好很方便解决分布式环境下的session同步的问题。

之前项目鉴权一直使用的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.1
spring.data.mongodb.port=27017
spring.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

@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();
    // 设置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里面怎么使用,怎么做不同权限的鉴权工作那就在自己的代码里面实现就行。

文章来源:
http://www.tianshangkun.com/2017/11/10/SpringBoot%E9%9B%86%E6%88%90Shiro%E5%B9%B6%E7%94%A8MongoDB%E5%81%9ASession%E5%AD%98%E5%82%A8/

更多参考内容:http://www.roncoo.com/article/index?tn=SpringBoot

相关实践学习
MongoDB数据库入门
MongoDB数据库入门实验。
快速掌握 MongoDB 数据库
本课程主要讲解MongoDB数据库的基本知识,包括MongoDB数据库的安装、配置、服务的启动、数据的CRUD操作函数使用、MongoDB索引的使用(唯一索引、地理索引、过期索引、全文索引等)、MapReduce操作实现、用户管理、Java对MongoDB的操作支持(基于2.x驱动与3.x驱动的完全讲解)。 通过学习此课程,读者将具备MongoDB数据库的开发能力,并且能够使用MongoDB进行项目开发。 &nbsp; 相关的阿里云产品:云数据库 MongoDB版 云数据库MongoDB版支持ReplicaSet和Sharding两种部署架构,具备安全审计,时间点备份等多项企业能力。在互联网、物联网、游戏、金融等领域被广泛采用。 云数据库MongoDB版(ApsaraDB for MongoDB)完全兼容MongoDB协议,基于飞天分布式系统和高可靠存储引擎,提供多节点高可用架构、弹性扩容、容灾、备份回滚、性能优化等解决方案。 产品详情: https://www.aliyun.com/product/mongodb
相关文章
|
1月前
|
NoSQL Java MongoDB
Springboot WebFlux项目结合mongodb进行crud
这篇文章介绍了如何使用Spring Boot WebFlux框架结合MongoDB进行基本的CRUD(创建、读取、更新、删除)操作,包括项目设置、实体类和Repository的创建、控制器的实现以及配置文件的编写。
47 0
Springboot WebFlux项目结合mongodb进行crud
|
2月前
|
安全 Java Apache
SpringBoot+Shiro(一)
SpringBoot+Shiro(一)
|
3月前
|
NoSQL Java MongoDB
SpringBoot中MongoDB的那些高级用法
本文探讨了在Spring Boot项目中使用MongoDB的多种方式及其高级用法。MongoDB作为一种NoSQL数据库,在某些场景下相较于SQL数据库有着独特的优势。文中详细介绍了在Spring Boot中使用MongoDB的三种主要方式:直接使用官方SDK、使用Spring JPA以及使用MongoTemplate,并对比分析了它们之间的差异。此外,文章深入讲解了Spring Data MongoDB提供的各种注解(如@Id, @Document, @Field等)以简化操作流程,并探讨了MongoTemplate监听器的应用,如设置主键值、记录日志等。
171 2
|
1月前
|
安全 Java 数据库
shiro学习一:了解shiro,学习执行shiro的流程。使用springboot的测试模块学习shiro单应用(demo 6个)
这篇文章是关于Apache Shiro权限管理框架的详细学习指南,涵盖了Shiro的基本概念、认证与授权流程,并通过Spring Boot测试模块演示了Shiro在单应用环境下的使用,包括与IniRealm、JdbcRealm的集成以及自定义Realm的实现。
44 3
shiro学习一:了解shiro,学习执行shiro的流程。使用springboot的测试模块学习shiro单应用(demo 6个)
|
1月前
|
Java API Apache
Springboot+shiro,完整教程,带你学会shiro
这篇文章提供了一个完整的Apache Shiro与Spring Boot结合使用的教程,包括Shiro的配置、使用以及在非Web和Web环境中进行身份验证和授权的示例。
66 2
Springboot+shiro,完整教程,带你学会shiro
|
1月前
|
前端开发 Java Apache
Springboot整合shiro,带你学会shiro,入门级别教程,由浅入深,完整代码案例,各位项目想加这个模块的人也可以看这个,又或者不会mybatis-plus的也可以看这个
本文详细讲解了如何整合Apache Shiro与Spring Boot项目,包括数据库准备、项目配置、实体类、Mapper、Service、Controller的创建和配置,以及Shiro的配置和使用。
318 1
Springboot整合shiro,带你学会shiro,入门级别教程,由浅入深,完整代码案例,各位项目想加这个模块的人也可以看这个,又或者不会mybatis-plus的也可以看这个
|
1月前
|
SQL NoSQL Java
springboot操作nosql的mongodb,或者是如何在mongodb官网创建服务器并进行操作
本文介绍了如何在Spring Boot中操作NoSQL数据库MongoDB,包括在MongoDB官网创建服务器、配置Spring Boot项目、创建实体类、仓库类、服务类和控制器类,以及如何进行测试。
19 1
springboot操作nosql的mongodb,或者是如何在mongodb官网创建服务器并进行操作
|
1月前
|
NoSQL Java Redis
shiro学习四:使用springboot整合shiro,正常的企业级后端开发shiro认证鉴权流程。使用redis做token的过滤。md5做密码的加密。
这篇文章介绍了如何使用Spring Boot整合Apache Shiro框架进行后端开发,包括认证和授权流程,并使用Redis存储Token以及MD5加密用户密码。
30 0
shiro学习四:使用springboot整合shiro,正常的企业级后端开发shiro认证鉴权流程。使用redis做token的过滤。md5做密码的加密。
|
19天前
|
JavaScript NoSQL Java
CC-ADMIN后台简介一个基于 Spring Boot 2.1.3 、SpringBootMybatis plus、JWT、Shiro、Redis、Vue quasar 的前后端分离的后台管理系统
CC-ADMIN后台简介一个基于 Spring Boot 2.1.3 、SpringBootMybatis plus、JWT、Shiro、Redis、Vue quasar 的前后端分离的后台管理系统
32 0
|
3月前
|
SQL Java 数据库连接
springboot+mybatis+shiro项目中使用shiro实现登录用户的权限验证。权限表、角色表、用户表。从不同的表中收集用户的权限、
这篇文章介绍了在Spring Boot + MyBatis + Shiro项目中,如何使用Shiro框架实现登录用户的权限验证,包括用户、角色和权限表的设计,以及通过多个表查询来收集和验证用户权限的方法和代码实现。
springboot+mybatis+shiro项目中使用shiro实现登录用户的权限验证。权限表、角色表、用户表。从不同的表中收集用户的权限、

热门文章

最新文章

下一篇
无影云桌面