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

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

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

      shiro的使用2 靈活使用shiro的密碼服務模塊

      shiro最閃亮的四大特征是認證,授權,加密,會話管理
      上一篇已經演示了如何使用shiro的授權模塊,有了shiro這個利器,可以以統一的編碼方式對用戶的登入,登出,認證進行管理,相當的優雅。
      為了提高應用系統的安全性,這里主要關注shiro提供的密碼服務模塊;

      1,加密工具類的熟悉

       

      首先來個結構圖,看看shiro哥哥提供了哪些加密工具類:

      image

       

      為此,寫了一個工具類來探測和熟悉這些工具類的使用:

      package com.util;
      import com.domain.User;
      import com.google.common.base.Preconditions;
      import com.google.common.base.Strings;
      import com.sun.crypto.provider.AESKeyGenerator;
      import org.apache.shiro.codec.Base64;
      import org.apache.shiro.codec.CodecSupport;
      import org.apache.shiro.codec.H64;
      import org.apache.shiro.codec.Hex;
      import org.apache.shiro.crypto.AesCipherService;
      import org.apache.shiro.crypto.SecureRandomNumberGenerator;
      import org.apache.shiro.crypto.hash.Md5Hash;
      import java.security.Key;
      /**
      * User: cutter.li
      * Date: 2014/6/27 0027
      * Time: 16:49
      * 備注: shiro進行加密解密的工具類封裝
      */
      public final class EndecryptUtils {
          /**
           * base64進制加密
           *
           * @param password
           * @return
           */
          public static String encrytBase64(String password) {
              Preconditions.checkArgument(!Strings.isNullOrEmpty(password), "不能為空");
              byte[] bytes = password.getBytes();
              return Base64.encodeToString(bytes);
          }
          /**
           * base64進制解密
           * @param cipherText
           * @return
           */
          public static String decryptBase64(String cipherText) {
              Preconditions.checkArgument(!Strings.isNullOrEmpty(cipherText), "消息摘要不能為空");
              return Base64.decodeToString(cipherText);
          }
          /**
           * 16進制加密
           *
           * @param password
           * @return
           */
          public static String encrytHex(String password) {
              Preconditions.checkArgument(!Strings.isNullOrEmpty(password), "不能為空");
              byte[] bytes = password.getBytes();
              return Hex.encodeToString(bytes);
          }
          /**
           * 16進制解密
           * @param cipherText
           * @return
           */
          public static String decryptHex(String cipherText) {
              Preconditions.checkArgument(!Strings.isNullOrEmpty(cipherText), "消息摘要不能為空");
              return new String(Hex.decode(cipherText));
          }
          public static String generateKey()
          {
              AesCipherService aesCipherService=new AesCipherService();
              Key key=aesCipherService.generateNewKey();
              return Base64.encodeToString(key.getEncoded());
          }
          /**
           * 對密碼進行md5加密,并返回密文和salt,包含在User對象中
           * @param username 用戶名
           * @param password 密碼
           * @return 密文和salt
           */
          public static User md5Password(String username,String password){
              Preconditions.checkArgument(!Strings.isNullOrEmpty(username),"username不能為空");
              Preconditions.checkArgument(!Strings.isNullOrEmpty(password),"password不能為空");
              SecureRandomNumberGenerator secureRandomNumberGenerator=new SecureRandomNumberGenerator();
              String salt= secureRandomNumberGenerator.nextBytes().toHex();
              //組合username,兩次迭代,對密碼進行加密
              String password_cipherText= new Md5Hash(password,username+salt,2).toBase64();
              User user=new User();
              user.setPassword(password_cipherText);
              user.setSalt(salt);
              user.setUsername(username);
              return user;
          }
          public static void main(String[] args) {
              String password = "admin";
              String cipherText = encrytHex(password);
              System.out.println(password + "hex加密之后的密文是:" + cipherText);
              String decrptPassword=decryptHex(cipherText);
              System.out.println(cipherText + "hex解密之后的密碼是:" + decrptPassword);
              String cipherText_base64 = encrytBase64(password);
              System.out.println(password + "base64加密之后的密文是:" + cipherText_base64);
              String decrptPassword_base64=decryptBase64(cipherText_base64);
              System.out.println(cipherText_base64 + "base64解密之后的密碼是:" + decrptPassword_base64);
              String h64=  H64.encodeToString(password.getBytes());
              System.out.println(h64);
              String salt="7road";
              String cipherText_md5= new Md5Hash(password,salt,4).toHex();
              System.out.println(password+"通過md5加密之后的密文是:"+cipherText_md5);
              System.out.println(generateKey());
              System.out.println("==========================================================");
              AesCipherService aesCipherService=new AesCipherService();
              aesCipherService.setKeySize(128);
              Key key=aesCipherService.generateNewKey();
              String aes_cipherText= aesCipherService.encrypt(password.getBytes(),key.getEncoded()).toHex();
              System.out.println(password+" aes加密的密文是:"+aes_cipherText);
              String aes_mingwen=new String(aesCipherService.decrypt(Hex.decode(aes_cipherText),key.getEncoded()).getBytes());
              System.out.println(aes_cipherText+" aes解密的明文是:"+aes_mingwen);
          }
      }

      2,一個綜合點的例子,配置帳號的密碼生成方式,并利用ehcache,設定輸錯密碼多少次,用戶被鎖定一個小時;

      1,提供一個ehcache的簡單實用類

      package com.util.cache;
      import net.sf.ehcache.Cache;
      import net.sf.ehcache.CacheManager;
      import net.sf.ehcache.Element;
      import net.sf.ehcache.config.CacheConfiguration;
      import net.sf.ehcache.store.MemoryStoreEvictionPolicy;
      /**
      * User: cutter.li
      * Date: 2014/6/30 0030
      * Time: 15:32
      * 備注: ehcache的緩存工具類
      */
      public final class EhcacheUtil {
          private static final CacheManager cacheManager = CacheManager.getInstance();
          /**
           * 創建ehcache緩存,創建之后的有效期是1小時
           */
         private static Cache cache = new Cache(new CacheConfiguration("systemCache", 5000).memoryStoreEvictionPolicy(MemoryStoreEvictionPolicy.FIFO).timeoutMillis(300).timeToLiveSeconds( 60 * 60));
          static {
              cacheManager.addCache(cache);

          }

          public static void putItem(String key, Object item) {
              if (cache.get(key) != null) {
                  cache.remove(key);
              }
              Element element = new Element(key, item);
              cache.put(element);
          }
          public static void removeItem(String key) {
              cache.remove(key);
          }
          public static void updateItem(String key, Object value) {
              putItem(key, value);
          }
          public static Object getItem(String key) {
              Element element=  cache.get(key);
              if(null!=element)
              {
                  return element.getObjectValue();
              }
              return null;
          }
      }

       

      2,提供加密和校驗密文的方法

       

      /**
           * 對密碼進行md5加密,并返回密文和salt,包含在User對象中
           * @param username 用戶名
           * @param password 密碼
           * @return 密文和salt
           */
          public static User md5Password(String username,String password){
              Preconditions.checkArgument(!Strings.isNullOrEmpty(username),"username不能為空");
              Preconditions.checkArgument(!Strings.isNullOrEmpty(password),"password不能為空");
              SecureRandomNumberGenerator secureRandomNumberGenerator=new SecureRandomNumberGenerator();
              String salt= secureRandomNumberGenerator.nextBytes().toHex();
              //組合username,兩次迭代,對密碼進行加密
              String password_cipherText= new Md5Hash(password,username+salt,2).toHex();
              User user=new User();
              user.setPassword(password_cipherText);
              user.setSalt(salt);
              user.setUsername(username);
              return user;
          }
          /**
           * 通過username,password,salt,校驗密文是否匹配 ,校驗規則其實在配置文件中,這里為了清晰,寫下來
           * @param username 用戶名
           * @param password 原密碼
           * @param salt  鹽
           * @param md5cipherText 密文
           * @return
           */
          public static  boolean checkMd5Password(String username,String password,String salt,String md5cipherText)
          {
              Preconditions.checkArgument(!Strings.isNullOrEmpty(username),"username不能為空");
              Preconditions.checkArgument(!Strings.isNullOrEmpty(password),"password不能為空");
              Preconditions.checkArgument(!Strings.isNullOrEmpty(md5cipherText),"md5cipherText不能為空");
              //組合username,兩次迭代,對密碼進行加密
              String password_cipherText= new Md5Hash(password,username+salt,2).toHex();
              return md5cipherText.equals(password_cipherText);
          }

      3,配置認證的數據源使用的密碼校驗接口

         <bean id="myRealm" class="com.util.MysqlJdbcRealM">
              <property name="credentialsMatcher" ref="passwordMatcher"></property>
          </bean>
          <bean id="passwordMatcher" class="com.util.LimitRetryHashedMatcher">
         <property name="hashAlgorithmName" value="md5"></property>
              <property name="hashIterations" value="2"></property>
              <property name="storedCredentialsHexEncoded" value="true"></property>

          </bean>


       

      4,注冊和登錄方法的修改

        /**
           * 用戶注冊
           *
           * @param entity
           * @return
           */
          @Override
          public ResponseEntity<Map> createSubmit(User entity) {
              //加密用戶輸入的密碼,得到密碼的摘要和鹽,保存到數據庫
            User user = EndecryptUtils.md5Password(entity.getUsername(), entity.getPassword());
              entity.setPassword(user.getPassword());
              entity.setSalt(user.getSalt());
              Map<String, Object> map = Maps.newHashMap();
              try {
                  boolean createResult = service.modify(entity, OperationType.create);
                  map.put("success", createResult);
              } catch (Exception e) {
                  e.printStackTrace();
              }
              return new ResponseEntity<Map>(map, HttpStatus.OK);
          }
      ------------------------------------------------------------------華麗的分割線---------------------------------------------------------------------------------------------------
        @RequestMapping(value = "login", method = RequestMethod.POST)
          public ResponseEntity<Message> loginSubmit(String username, String password, String vcode, HttpServletRequest request) {
              message.setSuccess();
              validateLogin(message, username, password, vcode);
              try {
      //            String code = request.getSession().getAttribute(AppConstant.KAPTCHA_SESSION_KEY).toString();
      //            if (!vcode.equalsIgnoreCase(code)) {
      //                message.setCode(AppConstant.VALIDCODE_ERROR);
      //                message.setMsg("驗證碼錯誤");
      //            }
                  if (message.isSuccess()) {
                      Subject subject = SecurityUtils.getSubject();
                      subject.login(new UsernamePasswordToken(username, password,false));
                      if (subject.isAuthenticated()) {
                              message.setMsg("登錄成功");
                      } else {
                          message.setCode(AppConstant.USERNAME_NOTEXIST);
                          message.setMsg("用戶名/密碼錯誤");
                      }
                  }
              }catch (ExcessiveAttemptsException ex)
              {
                  message.setCode(AppConstant.USERNAME_NOTEXIST);
                  message.setMsg("帳號被鎖定1小時");
                  ex.printStackTrace();
              }
              catch (AuthenticationException ex){
                  message.setCode(AppConstant.USERNAME_NOTEXIST);
                  message.setMsg("用戶名/密碼錯誤");
                  ex.printStackTrace();
              }
              finally {
                  return new ResponseEntity<Message>(message, HttpStatus.OK);
              }
          }
      ---------------------------------------------------------------認證的修改-------------------------------------------------------------------------------------
          //登錄認證
          @Override
          protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
              UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) token;
              String username = String.valueOf(usernamePasswordToken.getUsername());
              User user = userService.findByUserName(username);
              SimpleAuthenticationInfo authenticationInfo = null;
              if (null != user) {
                  String password = new String(usernamePasswordToken.getPassword());
      //密碼校驗移交給了shiro的提供的一個接口實現類,所以這里注釋掉
      //            if (EndecryptUtils.checkMd5Password(username,password,user.getSalt(),user.getPassword())) {
                      authenticationInfo = new SimpleAuthenticationInfo(user.getUsername(), user.getPassword(), getName());
                      authenticationInfo.setCredentialsSalt(ByteSource.Util.bytes(username+user.getSalt()));
      //            }

              }
              return authenticationInfo;
          }


       

      5,重寫密碼校驗的方法

      package com.util;
      import com.util.cache.EhcacheUtil;
      import org.apache.shiro.authc.AuthenticationInfo;
      import org.apache.shiro.authc.AuthenticationToken;
      import org.apache.shiro.authc.ExcessiveAttemptsException;
      import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
      import java.util.concurrent.atomic.AtomicInteger;
      /**
      * User: cutter.li
      * Date: 2014/6/30 0030
      * Time: 15:22
      * 備注: 限制登錄次數,如果5次出錯,鎖定1個小時
      */
      public class LimitRetryHashedMatcher extends HashedCredentialsMatcher {
          @Override
          public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
              String username = (String) token.getPrincipal();
      //retrycount + 1
              Object element = EhcacheUtil.getItem(username);
              if (element == null) {
                  EhcacheUtil.putItem(username, 1);
                  element=0;
              }else{
                  int count=Integer.parseInt(element.toString())+1;
                  element=count;
                  EhcacheUtil.putItem(username,element);
              }
              AtomicInteger retryCount = new AtomicInteger(Integer.parseInt(element.toString()));
              if (retryCount.incrementAndGet() > 5) {
      //if retrycount >5 throw
                  throw new ExcessiveAttemptsException();
              }
              boolean matches = super.doCredentialsMatch(token, info);
              if (matches) {
      //clear retrycount
                  EhcacheUtil.removeItem(username);
              }
              return matches;

          }
      }

       

      6,搞定收工


      連續輸錯5次密碼之后,出現如下提示;

      image

      7,小結

      通過封裝常用的加密解密工具類,降低了對jdk自帶密碼工具類的學習成本

      可以靈活定義密碼的生成和判斷方式,并改變密碼判斷過程的邏輯;

      posted @ 2014-07-01 10:23  李福春  閱讀(42374)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 九色国产精品一区二区久久| 亚洲av一本二本三本| 中文字幕成人精品久久不卡 | 国产绿帽在线视频看| 亚洲成av人在线播放无码| 永久免费AV无码国产网站| 婺源县| 亚洲曰韩欧美在线看片| 亚洲精品国产一二三区| 欧美性大战xxxxx久久久| 人人妻人人澡人人爽人人精品av| 国产熟女激情一区二区三区| 亚洲综合色婷婷中文字幕| 国产免费视频一区二区| 极品一区二区三区水蜜桃| 香蕉亚洲欧洲在线一区| 中文字幕无码视频手机免费看| 午夜福利激情一区二区三区| 国产精品久久无码不卡黑寡妇| 国产乱色国产精品免费视频| 亚洲人成人一区二区三区| 亚洲欧洲色图片网站| 国产亚洲精品久久综合阿香| 亚洲一区二区三区四区| 在线看片免费人成视频久网| 吃奶还摸下面动态图gif| 天堂中文8资源在线8| 97精品国产91久久久久久久| 国内少妇偷人精品免费| 性一交一黄一片| 亚洲人成网站在小说| 精品国产中文字幕第一页| 久久久精品国产精品久久| 99久久精品国产一区二区蜜芽| 日韩大片看一区二区三区| 国产中文字幕在线一区| 少妇粗大进出白浆嘿嘿视频| 久久精品国产亚洲av高| 亚洲第一狼人天堂网伊人| 99久久国产宗和精品1上映| 九九热在线观看精品视频|