之前项目鉴权一直使用的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里面怎么使用,怎么做不同权限的鉴权工作那就在自己的代码里面实现就行。

文章来源:

dhttp://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

SpringBoot集成Shiro并用MongoDB做Session存储的更多相关文章

  1. SpringBoot集成Shiro 实现动态加载权限

    一.前言 本文小编将基于 SpringBoot 集成 Shiro 实现动态uri权限,由前端vue在页面配置uri,Java后端动态刷新权限,不用重启项目,以及在页面分配给用户 角色 . 按钮 .ur ...

  2. SpringBoot学习笔记(五):SpringBoot集成lombok工具、SpringBoot集成Shiro安全框架

    SpringBoot集成lombok工具 什么是lombok? 自动生成setget方法,构造函数,打印日志 官网:http://projectlombok.org/features/index. 平 ...

  3. springboot集成shiro实现权限认证

    github:https://github.com/peterowang/shiro 基于上一篇:springboot集成shiro实现身份认证 1.加入UserController package ...

  4. springboot集成shiro 实现权限控制(转)

    shiro apache shiro 是一个轻量级的身份验证与授权框架,与spring security 相比较,简单易用,灵活性高,springboot本身是提供了对security的支持,毕竟是自 ...

  5. 【Shiro】SpringBoot集成Shiro

    项目版本: springboot2.x shiro:1.3.2 Maven配置: <dependency> <groupId>org.apache.shiro</grou ...

  6. SpringBoot集成Shiro安全框架

    跟着我的步骤:先运行起来再说 Spring集成Shiro的GitHub:https://github.com/yueshutong/shiro-imooc 一:导包 <!-- Shiro安全框架 ...

  7. springboot集成redis使用redis作为session报错ClassNotFoundException类RememberMeServices

    springboot 集成redis使用redis作为缓存,会报错的问题. 错误信息: java.lang.IllegalStateException: Error processing condit ...

  8. SpringBoot集成Shiro实现权限控制

    Shiro简介 Apache Shiro是一个功能强大且易于使用的Java安全框架,用于执行身份验证,授权,加密和会话管理.使用Shiro易于理解的API,您可以快速轻松地保护任何应用程序-从最小的移 ...

  9. springboot 集成shiro

    首先看下shiro configuration 的配置,重要部分用红色标出了 package cn.xiaojf.today.shiro.configuration; import at.pollux ...

随机推荐

  1. ionic2+Angular web端 实现微信分享以及如何跳转回分享出去的页面

    微信分享,首先参考微信JS-SDK开发文档. step1:在启动文件index.html中引入微信js文件: <script src="http://res.wx.qq.com/ope ...

  2. nodejs和npm的安装

    下载nodejs的压缩包 网址:https://nodejs.org/en/ 下载以tar.xz结尾的包例如:node-v8.9.4-linux-x64.tar.xz 上传包到制定的目录 可以用lrz ...

  3. levmar ndk 编译

         levmar是一个强大的和高效率的C/C++库,采用Levenberg - 马奎德(LM)优化算法, 主要是为了解决非线性最小二乘问题.官网是:http://users.ics.forth. ...

  4. 高可用的MongoDB集群

    1.序言 MongoDB 是一个可扩展的高性能,开源,模式自由,面向文档的数据库. 它使用 C++编写.MongoDB 包含一下特点: l  面向集合的存储:适合存储对象及JSON形式的数据. l ...

  5. 手把手教你用.NET Core写爬虫

    写在前面 自从上一个项目58HouseSearch从.NET迁移到.NET core之后,磕磕碰碰磨蹭了一个月才正式上线到新版本. 然后最近又开了个新坑,搞了个Dy2018Crawler用来爬dy20 ...

  6. 《HelloGitHub》第 23 期

    公告 新的一年,不忘初心,从新开始.加油! <HelloGitHub>第 23 期 兴趣是最好的老师,HelloGitHub 就是帮你找到兴趣! 简介 分享 GitHub 上有趣.入门级的 ...

  7. Hibernate学习(一)创建数据表

    (1)生成数据库表的创建: // 默认读取hibernate.cfg.xml文件 Configuration cfg = new Configuration().configure(); // 生成并 ...

  8. iOS视频直播

    视频直播技术点 视频直播,可以分为 采集,前处理,编码,传输, 服务器处理,解码,渲染 采集: iOS系统因为软硬件种类不多, 硬件适配性比较好, 所以比较简单. 而Android端市面上机型众多, ...

  9. Nginx location配置详细解释

    nginx location配置详细解释 语法规则: location [=|~|~*|^~] /uri/ { - } = 开头表示精确匹配 ^~ 开头表示uri以某个常规字符串开头,理解为匹配 ur ...

  10. 转载 USB固件分析

    http://1438431234.spaces.eepw.com.cn/articles/article/item/114022 0x00000000 0x0001fff0 大小 0x1fff1 = ...