<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      SpringBoot + Redis + Shiro 實現權限管理(轉)

      概述

        本文基于網上整理,為了實現將Shiro框架的session存儲到redis里面,進而實現基于Niginx負載均衡,多站點部署;

      maven下shiro依賴

      <!-- shiro -->
              <dependency>
                  <groupId>org.apache.shiro</groupId>
                  <artifactId>shiro-spring</artifactId>
                  <version>1.4.0</version>
              </dependency>
              <dependency>
                  <groupId>org.apache.shiro</groupId>
                  <artifactId>shiro-ehcache</artifactId>
                  <version>1.4.0</version>
              </dependency>
      
              <!-- shiro+redis緩存插件 -->
              <dependency>
                  <groupId>org.crazycake</groupId>
                  <artifactId>shiro-redis</artifactId>
                  <version>2.4.2.1-RELEASE</version>
              </dependency>

      主要代碼編寫

      1、ShiroConfig配置

      package com.chaoqi.springboot_shiro_redis.config;
      
      import com.chaoqi.springboot_shiro_redis.secutity.KickoutSessionControlFilter;
      import com.chaoqi.springboot_shiro_redis.secutity.MyShiroRealm;
      import org.apache.shiro.mgt.SecurityManager;
      import org.apache.shiro.spring.LifecycleBeanPostProcessor;
      import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
      import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
      import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
      import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
      import org.crazycake.shiro.RedisCacheManager;
      import org.crazycake.shiro.RedisManager;
      import org.crazycake.shiro.RedisSessionDAO;
      import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
      import org.springframework.context.annotation.Bean;
      import org.springframework.context.annotation.Configuration;
      
      import javax.servlet.Filter;
      import java.util.LinkedHashMap;
      import java.util.Map;
      
      
      @Configuration
      public class ShiroConfig {
      

          @Value("${redis.host}")
          private String redisHost;

          @Value("${redis.port}")
          private String redisPort;

          @Bean
          public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
              ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
              shiroFilterFactoryBean.setSecurityManager(securityManager);
              // 沒有登陸的用戶只能訪問登陸頁面
              shiroFilterFactoryBean.setLoginUrl("/auth/login");
              // 登錄成功后要跳轉的鏈接
              shiroFilterFactoryBean.setSuccessUrl("/auth/index");
              // 未授權界面; ----這個配置了沒卵用,具體原因想深入了解的可以自行百度
              //shiroFilterFactoryBean.setUnauthorizedUrl("/auth/403");
              //自定義攔截器
              Map<String, Filter> filtersMap = new LinkedHashMap<String, Filter>();
              //限制同一帳號同時在線的個數。
              filtersMap.put("kickout", kickoutSessionControlFilter());
              shiroFilterFactoryBean.setFilters(filtersMap);
              // 權限控制map.
              Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();
              filterChainDefinitionMap.put("/css/**", "anon");
              filterChainDefinitionMap.put("/js/**", "anon");
              filterChainDefinitionMap.put("/img/**", "anon");
              filterChainDefinitionMap.put("/auth/login", "anon");
              filterChainDefinitionMap.put("/auth/logout", "logout");
              filterChainDefinitionMap.put("/auth/kickout", "anon");
              filterChainDefinitionMap.put("/**", "authc,kickout");
              shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
              return shiroFilterFactoryBean;
          }
      
          @Bean
          public SecurityManager securityManager() {
              DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
              // 設置realm.
              securityManager.setRealm(myShiroRealm());
              // 自定義緩存實現 使用redis
              securityManager.setCacheManager(cacheManager());
              // 自定義session管理 使用redis
              securityManager.setSessionManager(sessionManager());
              return securityManager;
          }
      
          /**
           * 身份認證realm; (這個需要自己寫,賬號密碼校驗;權限等)
           *
           * @return
           */
          @Bean
          public MyShiroRealm myShiroRealm() {
              MyShiroRealm myShiroRealm = new MyShiroRealm();
              return myShiroRealm;
          }
      
          /**
           * cacheManager 緩存 redis實現
           * 使用的是shiro-redis開源插件
           *
           * @return
           */
          public RedisCacheManager cacheManager() {
              RedisCacheManager redisCacheManager = new RedisCacheManager();
              redisCacheManager.setRedisManager(redisManager());
              return redisCacheManager;
          }
      
          /**
           * 配置shiro redisManager
           * 使用的是shiro-redis開源插件
           *
           * @return
           */
          public RedisManager redisManager() {
              RedisManager redisManager = new RedisManager();
              redisManager.setHost(redisHost);
              redisManager.setPort(redisPort);
              redisManager.setExpire(1800);// 配置緩存過期時間
              redisManager.setTimeout(0);
              // redisManager.setPassword(password);
              return redisManager;
          }
      
          /**
           * Session Manager
           * 使用的是shiro-redis開源插件
           */
          @Bean
          public DefaultWebSessionManager sessionManager() {
              DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
              sessionManager.setSessionDAO(redisSessionDAO());
              return sessionManager;
          }
      
          /**
           * RedisSessionDAO shiro sessionDao層的實現 通過redis
           * 使用的是shiro-redis開源插件
           */
          @Bean
          public RedisSessionDAO redisSessionDAO() {
              RedisSessionDAO redisSessionDAO = new RedisSessionDAO();
              redisSessionDAO.setRedisManager(redisManager());
              return redisSessionDAO;
          }
      
          /**
           * 限制同一賬號登錄同時登錄人數控制
           *
           * @return
           */
          @Bean
          public KickoutSessionControlFilter kickoutSessionControlFilter() {
              KickoutSessionControlFilter kickoutSessionControlFilter = new KickoutSessionControlFilter();
              kickoutSessionControlFilter.setCacheManager(cacheManager());
              kickoutSessionControlFilter.setSessionManager(sessionManager());
              kickoutSessionControlFilter.setKickoutAfter(false);
              kickoutSessionControlFilter.setMaxSession(1);
              kickoutSessionControlFilter.setKickoutUrl("/auth/kickout");
              return kickoutSessionControlFilter;
          }
      
      
          /***
           * 授權所用配置
           *
           * @return
           */
          @Bean
          public DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator() {
              DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
              defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);
              return defaultAdvisorAutoProxyCreator;
          }
      
          /***
           * 使授權注解起作用不如不想配置可以在pom文件中加入
           * <dependency>
           *<groupId>org.springframework.boot</groupId>
           *<artifactId>spring-boot-starter-aop</artifactId>
           *</dependency>
           * @param securityManager
           * @return
           */
          @Bean
          public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager){
              AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
              authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
              return authorizationAttributeSourceAdvisor;
          }
      
          /**
           * Shiro生命周期處理器
           *
           */
          @Bean
          public static LifecycleBeanPostProcessor getLifecycleBeanPostProcessor() {
              return new LifecycleBeanPostProcessor();
          }
      
      }
      

       2、自定義Realm

      package com.chaoqi.springboot_shiro_redis.secutity;
      
      import com.chaoqi.springboot_shiro_redis.service.SysRoleService;
      import com.chaoqi.springboot_shiro_redis.service.UserService;
      import com.chaoqi.springboot_shiro_redis.dao.domain.SysUser;
      import org.apache.shiro.authc.*;
      import org.apache.shiro.authz.AuthorizationInfo;
      import org.apache.shiro.authz.SimpleAuthorizationInfo;
      import org.apache.shiro.realm.AuthorizingRealm;
      import org.apache.shiro.subject.PrincipalCollection;
      import org.slf4j.LoggerFactory;
      import org.springframework.beans.factory.annotation.Autowired;
      
      import java.util.*;
      
      public class MyShiroRealm extends AuthorizingRealm {
          private static org.slf4j.Logger logger = LoggerFactory.getLogger(MyShiroRealm.class);
      
          //如果項目中用到了事物,@Autowired注解會使事物失效,可以自己用get方法獲取值
          @Autowired
          private SysRoleService roleService;
          @Autowired
          private UserService userService;
      
          /**
           * 認證信息.(身份驗證) : Authentication 是用來驗證用戶身份
           *
           */
          @Override
          protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) throws AuthenticationException {
              logger.info("---------------- 執行 Shiro 憑證認證 ----------------------");
              UsernamePasswordToken token = (UsernamePasswordToken) authcToken;
              String name = token.getUsername();
              String password = String.valueOf(token.getPassword());
              SysUser user = new SysUser();
              user.setUserName(name);
              user.setPassWord(password);
              // 從數據庫獲取對應用戶名密碼的用戶
              SysUser userList = userService.getUser(user);
              if (userList != null) {
                  // 用戶為禁用狀態
                  if (userList.getUserEnable() != 1) {
                      throw new DisabledAccountException();
                  }
                  logger.info("---------------- Shiro 憑證認證成功 ----------------------");
                  SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(
                          userList, //用戶
                          userList.getPassWord(), //密碼
                          getName()  //realm name
                  );
                  return authenticationInfo;
              }
              throw new UnknownAccountException();
          }
      
          /**
           * 授權
           */
          @Override
          protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
              logger.info("---------------- 執行 Shiro 權限獲取 ---------------------");
              Object principal = principals.getPrimaryPrincipal();
              SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
              if (principal instanceof SysUser) {
                  SysUser userLogin = (SysUser) principal;
                  Set<String> roles = roleService.findRoleNameByUserId(userLogin.getId());
                  authorizationInfo.addRoles(roles);
      
                  Set<String> permissions = userService.findPermissionsByUserId(userLogin.getId());
                  authorizationInfo.addStringPermissions(permissions);
              }
              logger.info("---- 獲取到以下權限 ----");
              logger.info(authorizationInfo.getStringPermissions().toString());
              logger.info("---------------- Shiro 權限獲取成功 ----------------------");
              return authorizationInfo;
          }
      
      }

      3、限制并發人數登陸

      package com.chaoqi.springboot_shiro_redis.secutity;
      
      import com.alibaba.fastjson.JSON;
      import com.chaoqi.springboot_shiro_redis.dao.domain.SysUser;
      import org.apache.shiro.cache.Cache;
      import org.apache.shiro.cache.CacheManager;
      import org.apache.shiro.session.Session;
      import org.apache.shiro.session.mgt.DefaultSessionKey;
      import org.apache.shiro.session.mgt.SessionManager;
      import org.apache.shiro.subject.Subject;
      import org.apache.shiro.web.filter.AccessControlFilter;
      import org.apache.shiro.web.util.WebUtils;
      
      import javax.servlet.ServletRequest;
      import javax.servlet.ServletResponse;
      import javax.servlet.http.HttpServletRequest;
      import java.io.IOException;
      import java.io.PrintWriter;
      import java.io.Serializable;
      import java.util.Deque;
      import java.util.HashMap;
      import java.util.LinkedList;
      import java.util.Map;
      
      public class KickoutSessionControlFilter extends AccessControlFilter {
      
          private String kickoutUrl; //踢出后到的地址
          private boolean kickoutAfter = false; //踢出之前登錄的/之后登錄的用戶 默認踢出之前登錄的用戶
          private int maxSession = 1; //同一個帳號最大會話數 默認1
      
          private SessionManager sessionManager;
          private Cache<String, Deque<Serializable>> cache;
      
          public void setKickoutUrl(String kickoutUrl) {
              this.kickoutUrl = kickoutUrl;
          }
      
          public void setKickoutAfter(boolean kickoutAfter) {
              this.kickoutAfter = kickoutAfter;
          }
      
          public void setMaxSession(int maxSession) {
              this.maxSession = maxSession;
          }
      
          public void setSessionManager(SessionManager sessionManager) {
              this.sessionManager = sessionManager;
          }
          //設置Cache的key的前綴
          public void setCacheManager(CacheManager cacheManager) {
              this.cache = cacheManager.getCache("shiro_redis_cache");
          }
      
          @Override
          protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception {
              return false;
          }
      
          @Override
          protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
              Subject subject = getSubject(request, response);
              if(!subject.isAuthenticated() && !subject.isRemembered()) {
                  //如果沒有登錄,直接進行之后的流程
                  return true;
              }
      
      
              Session session = subject.getSession();
              SysUser user = (SysUser) subject.getPrincipal();
              String username = user.getUserName();
              Serializable sessionId = session.getId();
      
              //讀取緩存   沒有就存入
              Deque<Serializable> deque = cache.get(username);
      
              //如果此用戶沒有session隊列,也就是還沒有登錄過,緩存中沒有
              //就new一個空隊列,不然deque對象為空,會報空指針
              if(deque==null){
                  deque = new LinkedList<Serializable>();
              }
      
              //如果隊列里沒有此sessionId,且用戶沒有被踢出;放入隊列
              if(!deque.contains(sessionId) && session.getAttribute("kickout") == null) {
                  //將sessionId存入隊列
                  deque.push(sessionId);
                  //將用戶的sessionId隊列緩存
                  cache.put(username, deque);
              }
      
              //如果隊列里的sessionId數超出最大會話數,開始踢人
              while(deque.size() > maxSession) {
                  Serializable kickoutSessionId = null;
                  if(kickoutAfter) { //如果踢出后者
                      kickoutSessionId = deque.removeFirst();
                      //踢出后再更新下緩存隊列
                      cache.put(username, deque);
                  } else { //否則踢出前者
                      kickoutSessionId = deque.removeLast();
                      //踢出后再更新下緩存隊列
                      cache.put(username, deque);
                  }
      
      
      
                  try {
                      //獲取被踢出的sessionId的session對象
                      Session kickoutSession = sessionManager.getSession(new DefaultSessionKey(kickoutSessionId));
                      if(kickoutSession != null) {
                          //設置會話的kickout屬性表示踢出了
                          kickoutSession.setAttribute("kickout", true);
                      }
                  } catch (Exception e) {//ignore exception
                  }
              }
      
              //如果被踢出了,直接退出,重定向到踢出后的地址
              if (session.getAttribute("kickout") != null) {
                  //會話被踢出了
                  try {
                      //退出登錄
                      subject.logout();
                  } catch (Exception e) { //ignore
                  }
                  saveRequest(request);
      
                  Map<String, String> resultMap = new HashMap<String, String>();
                  //判斷是不是Ajax請求
                  if ("XMLHttpRequest".equalsIgnoreCase(((HttpServletRequest) request).getHeader("X-Requested-With"))) {
                      resultMap.put("user_status", "300");
                      resultMap.put("message", "您已經在其他地方登錄,請重新登錄!");
                      //輸出json串
                      out(response, resultMap);
                  }else{
                      //重定向
                      WebUtils.issueRedirect(request, response, kickoutUrl);
                  }
                  return false;
              }
              return true;
          }
          private void out(ServletResponse hresponse, Map<String, String> resultMap)
                  throws IOException {
              try {
                  hresponse.setCharacterEncoding("UTF-8");
                  PrintWriter out = hresponse.getWriter();
                  out.println(JSON.toJSONString(resultMap));
                  out.flush();
                  out.close();
              } catch (Exception e) {
                  System.err.println("KickoutSessionFilter.class 輸出JSON異常,可以忽略。");
              }
          }
      }

      參考網址

      http://www.rzrgm.cn/caichaoqi/p/8900677.html

      http://www.rzrgm.cn/chenxbo/p/11002392.html

       

      posted @ 2020-02-25 18:20  jiajinhao  閱讀(760)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 亚洲综合精品中文字幕| 人妻av无码一区二区三区| 国产桃色在线成免费视频| 国产精品久久久一区二区三区| 伊人无码精品久久一区二区| 欧美福利电影A在线播放| 久久久久影院色老大2020| 国产福利视频区一区二区| 69精品丰满人妻无码视频a片| 光棍天堂在线手机播放免费| 国产精品白浆免费视频| 制服 丝袜 亚洲 中文 综合| 日韩高清亚洲日韩精品一区二区 | 国产又色又爽又黄的视频在线| 宁河县| caoporn免费视频公开| 国内视频偷拍久久伊人网| 粉嫩一区二区三区国产精品| 奇米777四色成人影视| 制服 丝袜 亚洲 中文 综合| 亚洲人成色77777| 国产亚洲一在无在线观看| 蜜臀av一区二区三区日韩| 粉嫩一区二区三区粉嫩视频| 国产一卡2卡三卡4卡免费网站| 日本不卡三区| 人人澡超碰碰97碰碰碰| 亚洲熟妇熟女久久精品综合| 亚洲国产精品综合久久20| 亚洲高清国产拍精品熟女 | 人妻系列无码专区69影院| 午夜毛片不卡免费观看视频| 亚洲国产码专区在线观看| 国产成人精品18| 自拍偷在线精品自拍偷免费| 国产99视频精品免费专区| 97人人添人人澡人人澡人人澡| 毛片av在线尤物一区二区| 亚洲精品区二区三区蜜桃| 国产精品污双胞胎在线观看| 亚洲精品区二区三区蜜桃|