SpringBoot集成Shiro并用MongoDB做Sessi

作者: 金桔文案 | 来源:发表于2018-01-04 11:20 被阅读199次

    之前项目鉴权一直使用的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

    相关文章

      网友评论

        本文标题:SpringBoot集成Shiro并用MongoDB做Sessi

        本文链接:https://www.haomeiwen.com/subject/yrxrnxtx.html