之前项目鉴权一直使用的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. 小甲鱼OD学习第12讲

    这次我们的任务是破解这个需要特定的注册码的软件,如下图 我们从字符串入手,输入register,搜索 我们点击    查找下一个,看看有什么有用的字符串,如下图 然后,在下方,我们发现了  Regis ...

  2. 定时跳转的两种方式(html + javaweb)

    html方式 <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <ti ...

  3. iOS 使用NTP时间同步服务

    githup上有相关开源库, ios-ntp 导入即可使用 NetworkClock *netClock = [NetworkClock sharedNetworkClock]; netClock.n ...

  4. dedecms判断当前页面是否为首页 织梦设置首页高亮

    做织梦网站导航栏时,我们一般需要设置当前栏目高亮显示,这个使用currentstyle就能直接实现,但是如果在首页时怎么让首页模块高亮呢? 织梦当前栏目高亮: <style>.hover{ ...

  5. 从零开始学Python--数据类型之字符串

    一.Python中的数据类型 ·   整数, 如 1 -100 ·   长整数, 是比较大的整数,Python 2里面有long长整数:Python 3里面没有 ·   浮点数 如 1.23.3E-2 ...

  6. 基于agenda的Nodejs定时任务管理框架搭建

    0.背景 在大型项目中,定时任务的应用场景越来越广.一般来说,按照微服务的思想,我们会将定时任务单独部署一套服务,核心的业务接口独立到另一个服务中,从而降低相互之间的耦合程度.在需要使用定时任务时,只 ...

  7. centos/linux下的安装vsftpd

    1.简介: vsftpd 是“very secure FTP daemon”的缩写,安全性是它的一个最大的特点.vsftpd 是一个 UNIX 类操作系统上运行的服务器的名字,ftp服务器软件 2.安 ...

  8. jdbc 报错解决办法

    刚刚看到一个童鞋出现了这个问题 其实这个问题很好解决 在工程中创建一个lib目录: 然后讲mysql包复制进去 然后对着包点击右键 build path就可以了 最后面再次运行就可以了 jar包地址下 ...

  9. 试着把.net的GC讲清楚(3)

    前两篇写的都是gc的一些概念和细节,这些东西对自己以后写代码有什么用,本篇我就准备将这些内容. root 第一篇文章中讲了GC在遍历存活对象的时候,都是从root开始的,root是一些对象的引用,例如 ...

  10. Effective Java 第三版——35. 使用实例属性替代序数

    Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...