日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 综合教程 >内容正文

综合教程

js加密后台加密解密以及验证码

發(fā)布時(shí)間:2024/8/26 综合教程 33 生活家
生活随笔 收集整理的這篇文章主要介紹了 js加密后台加密解密以及验证码 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

該文檔為轉(zhuǎn)載內(nèi)容:

    加密解密
    1 前端js加密概述
    2 前后端加密解密
            21 引用的js加密庫
            22 js加密解密
            23 Java端加密解密PKCS5Padding與js的Pkcs7一致
    驗(yàn)證碼
    1 概述
    2 驗(yàn)證碼生成器
    3 控制器使用驗(yàn)證碼 如 CodeController
    應(yīng)用
    1 loginhtml
    2 Controller
    4 實(shí)現(xiàn)思路

1. 加密解密
1.1 前端js加密概述

對(duì)系統(tǒng)安全性要求比較高,那么需要選擇https協(xié)議來傳輸數(shù)據(jù)。當(dāng)然很多情況下一般的web網(wǎng)站,如果安全要求不是很高的話,用http協(xié)議就可以了。在這種情況下,密碼的明文傳輸顯然是不合適的,因?yàn)槿绻?qǐng)求在傳輸過程中被截了,就可以直接拿明文密碼登錄網(wǎng)站了。
HTTPS(443)在HTTP(80)的基礎(chǔ)上加入了SSL(Secure Sockets Layer 安全套接層)協(xié)議,SSL依靠證書來驗(yàn)證服務(wù)器的身份,并為瀏覽器和服務(wù)器之間的通信加密。傳輸前用公鑰加密,服務(wù)器端用私鑰解密。

對(duì)于使用http協(xié)議的web前端的加密,只能防君子不能防小人。前端是完全暴露的,包括你的加密算法。
知道了加密算法,密碼都是可以破解的,只是時(shí)間問題。請(qǐng)看知乎上的一篇文章:對(duì)抗拖庫

所以加密是為了增加破解的時(shí)間成本,如果破解需要花費(fèi)的時(shí)間讓人難以接受,這也就達(dá)到了目的。

而為了保證數(shù)據(jù)庫中存儲(chǔ)的密碼更安全,則需要在后端用多種單向(非對(duì)稱)加密手段混合進(jìn)行加密存儲(chǔ)。

前端加密后端又需要解密,所以需要對(duì)稱加密算法,即前端使用 encrypted = encrypt(password+key),后端使用 password = decrypt(encrypted +key) ,前端只傳輸密碼與key加密后的字符串encrypted ,這樣即使請(qǐng)求被攔截了,也知道了加密算法,但是由于缺少key所以很難破解出明文密碼。所以這個(gè)key很關(guān)鍵。而這個(gè)key是由后端控制生成與銷毀的,用完即失效,所以即使可以模擬用加密后的密碼來發(fā)請(qǐng)求模擬登錄,但是key已經(jīng)失效了,后端還是驗(yàn)證不過的。

注意,如果本地環(huán)境本就是不安全的,key被知道了,那就瞬間就可以用解密算法破解出密碼了。這里只是假設(shè)傳輸?shù)倪^程中被截獲的情形。所以前端加密是防不了小人的。如果真要防,可以將加密算法的js文件進(jìn)行壓縮加密,不斷更新的手段來使js文件難以獲取,讓黑客難以獲取加密算法。變態(tài)的google就是這么干的,自己實(shí)現(xiàn)一個(gè)js虛擬機(jī),通過不斷更新加密混淆js文件讓加密算法難以獲取。這樣黑客不知道加密算法就無法破解了。

常用的對(duì)稱加密算法有DES、3DES(TripleDES)、AES、RC2、RC4、RC5和Blowfis。可以參考:常用加密算法的Java實(shí)現(xiàn)總結(jié)

這里采用js端與java端互通的AES加密算法。

1.2 前后端加密解密

1.2.1 引用的js加密庫

    Cryptojs下載

    <script src="${request.contextPath}/resources/plugins/jQuery/jquery-2.2.4.min.js"></script>
    <script src="${request.contextPath}/resources/cryptojs/aes.js"></script>
    <script src="${request.contextPath}/resources/cryptojs/mode-ecb-min.js"></script>

1.2.2 js加密解密

    var data = "888888";
    var srcs  = CryptoJS.enc.Utf8.parse(data);
    var key  = CryptoJS.enc.Utf8.parse('o7H8uIM2O5qv65l2');//Latin1 w8m31+Yy/Nw6thPsMpO5fg==
    function Encrypt(word){  

        var srcs = CryptoJS.enc.Utf8.parse(word);  
        var encrypted = CryptoJS.AES.encrypt(srcs, key, {mode:CryptoJS.mode.ECB,padding: CryptoJS.pad.Pkcs7});  
        return encrypted.toString();  
    }  
    function Decrypt(word){  

        var decrypt = CryptoJS.AES.decrypt(word, key, {mode:CryptoJS.mode.ECB,padding: CryptoJS.pad.Pkcs7});  
        return CryptoJS.enc.Utf8.stringify(decrypt).toString();  
    }

這里key是頁面加載的時(shí)候由服務(wù)器端生成的,用隱藏域保存。

1.2.3 Java端加密解密(PKCS5Padding與js的Pkcs7一致)

    package com.jykj.demo.util;

    import javax.crypto.Cipher;
    import javax.crypto.KeyGenerator;
    import javax.crypto.spec.SecretKeySpec;

    import org.apache.commons.codec.binary.Base64;

    import sun.misc.BASE64Decoder;

    public class EncryptUtil {
        private static final String KEY = "abcdefgabcdefg12";  
        private static final String ALGORITHMSTR = "AES/ECB/PKCS5Padding";  
        public static String base64Encode(byte[] bytes){  
            return Base64.encodeBase64String(bytes);  
        }  
        public static byte[] base64Decode(String base64Code) throws Exception{  
            return new BASE64Decoder().decodeBuffer(base64Code);  
        }  
        public static byte[] aesEncryptToBytes(String content, String encryptKey) throws Exception {  
            KeyGenerator kgen = KeyGenerator.getInstance("AES");  
            kgen.init(128);  
            Cipher cipher = Cipher.getInstance(ALGORITHMSTR);  
            cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(encryptKey.getBytes(), "AES"));  

            return cipher.doFinal(content.getBytes("utf-8"));  
        }  
        public static String aesEncrypt(String content, String encryptKey) throws Exception {  
            return base64Encode(aesEncryptToBytes(content, encryptKey));  
        }  
        public static String aesDecryptByBytes(byte[] encryptBytes, String decryptKey) throws Exception {  
            KeyGenerator kgen = KeyGenerator.getInstance("AES");  
            kgen.init(128);  

            Cipher cipher = Cipher.getInstance(ALGORITHMSTR);  
            cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(decryptKey.getBytes(), "AES"));  
            byte[] decryptBytes = cipher.doFinal(encryptBytes);  

            return new String(decryptBytes);  
        }  
        public static String aesDecrypt(String encryptStr, String decryptKey) throws Exception {  
            return aesDecryptByBytes(base64Decode(encryptStr), decryptKey);  
        }  


        /**
         * 測(cè)試
         * 
         */
        public static void main(String[] args) throws Exception {

            String content = "Test String么么噠";  //0gqIDaFNAAmwvv3tKsFOFf9P9m/6MWlmtB8SspgxqpWKYnELb/lXkyXm7P4sMf3e
            System.out.println("加密前:" + content);  

            System.out.println("加密密鑰和解密密鑰:" + KEY);  

            String encrypt = aesEncrypt(content, KEY);  
            System.out.println(encrypt.length()+":加密后:" + encrypt);  

            String decrypt = aesDecrypt(encrypt, KEY);  
            System.out.println("解密后:" + decrypt);  
        }
    }

2. 驗(yàn)證碼
2.1 概述

驗(yàn)證碼是用來區(qū)分人機(jī)的操作。
驗(yàn)證碼劃代的標(biāo)準(zhǔn)是人機(jī)識(shí)別過程中基于對(duì)人類知識(shí)的應(yīng)用。
第一代:標(biāo)準(zhǔn)驗(yàn)證碼
這一代驗(yàn)證碼是即是我們常見的圖形驗(yàn)證碼、語音驗(yàn)證碼,基于機(jī)器難以處理復(fù)雜的計(jì)算機(jī)視覺及語音識(shí)別問題,而人類卻可以輕松的識(shí)別來區(qū)分人類及機(jī)器。這一代驗(yàn)證碼初步利用了人類知識(shí)容易解答,而計(jì)算機(jī)難以解答的機(jī)制進(jìn)行人機(jī)判斷。

第二代:創(chuàng)新驗(yàn)證碼
第二代驗(yàn)證碼是基于第一代驗(yàn)證碼的核心思想(通過人類知識(shí)可以解答,而計(jì)算機(jī)難以解答的問題進(jìn)行人機(jī)判斷)而產(chǎn)生的創(chuàng)新的交互優(yōu)化型驗(yàn)證碼。第二代驗(yàn)證碼基于第一代驗(yàn)證碼的核心原理--“人機(jī)之間知識(shí)的差異”,拓展出大量創(chuàng)新型驗(yàn)證碼。

第三代:無知識(shí)型驗(yàn)證碼
第三代驗(yàn)證碼最大的特點(diǎn)是不再基于知識(shí)進(jìn)行人機(jī)判斷,而是基于人類固有的生物特征以及操作的環(huán)境信息綜合決策,來判斷是人類還是機(jī)器。無知識(shí)型驗(yàn)證碼最大特點(diǎn)即無需人類思考,從而不會(huì)打斷用戶操作,進(jìn)而提供更好的用戶體驗(yàn)。
如Google的新版ReCaptcha、阿里巴巴的滑動(dòng)驗(yàn)證。參考知乎 關(guān)于驗(yàn)證碼

2.2 驗(yàn)證碼生成器

    package com.jykj.demo.util;

    import java.awt.Color;
    import java.awt.Font;
    import java.awt.Graphics2D;
    import java.awt.image.BufferedImage;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.OutputStream;
    import java.util.Random;

    import javax.imageio.ImageIO;

    /**
     * 驗(yàn)證碼生成器
     * 
     */
    public class ValidateCode {
        // 圖片的寬度。
        private int width = 160;
        // 圖片的高度。
        private int height = 28;
        // 驗(yàn)證碼字符個(gè)數(shù)
        private int codeCount = 4;
        // 驗(yàn)證碼干擾線數(shù)
        private int lineCount = 150;
        // 驗(yàn)證碼
        private String code = null;
        // 驗(yàn)證碼圖片Buffer
        private BufferedImage buffImg = null;

        private char[] codeSequence = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'P', 'Q', 'R',
                'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '1', '2', '3', '4', '5', '6', '7', '8', '9' };

        public ValidateCode() {
            this.createCode();
        }

        /**
         * 
         * @param width
         *            圖片寬
         * @param height
         *            圖片高
         */
        public ValidateCode(int width, int height) {
            this.width = width;
            this.height = height;
            this.createCode();
        }

       /**
         * 
         * @param width
         *            圖片寬
         * @param height
         *            圖片高
         * @param codeCount
         *            字符個(gè)數(shù)
         * @param lineCount
         *            干擾線條數(shù)
         */
        public ValidateCode(int width, int height, int codeCount, int lineCount) {
            this.width = width;
            this.height = height;
            this.codeCount = codeCount;
            this.lineCount = lineCount;
            this.createCode();
        }
    
        public void createCode() {
            int x = 0, fontHeight = 0, codeY = 0;
            int red = 0, green = 0, blue = 0;

            x = width / (codeCount + 2);// 每個(gè)字符的寬度
            fontHeight = height - 2;// 字體的高度
            codeY = height - 4;

            // 圖像buffer
           buffImg = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
            Graphics2D g = buffImg.createGraphics();
            // 生成隨機(jī)數(shù)
            Random random = new Random();
            // 將圖像填充為白色
            g.setColor(Color.WHITE);
            g.fillRect(0, 0, width, height);
            // 創(chuàng)建字體
            Font font = new Font("Fixedsys", Font.BOLD, fontHeight);
            g.setFont(font);
            //干擾線
            for (int i = 0; i < lineCount; i++) {
                int xs = random.nextInt(width);
                int ys = random.nextInt(height);
                int xe = xs + random.nextInt(width / 8);
                int ye = ys + random.nextInt(height / 8);
                red = random.nextInt(255);
                green = random.nextInt(255);
                blue = random.nextInt(255);
                g.setColor(new Color(red, green, blue));
                g.drawLine(xs, ys, xe, ye);
            }

            // randomCode記錄隨機(jī)產(chǎn)生的驗(yàn)證碼
            StringBuffer randomCode = new StringBuffer();
            // 隨機(jī)產(chǎn)生codeCount個(gè)字符的驗(yàn)證碼。
            for (int i = 0; i < codeCount; i++) {
                String strRand = String.valueOf(codeSequence[random.nextInt(codeSequence.length)]);
                // 產(chǎn)生隨機(jī)的顏色值,讓輸出的每個(gè)字符的顏色值都將不同。
                red = random.nextInt(255);
                green = random.nextInt(255);
                blue = random.nextInt(255);
                g.setColor(new Color(red, green, blue));
                g.drawString(strRand, (i + 1) * x, codeY);
                // 將產(chǎn)生的四個(gè)隨機(jī)數(shù)組合在一起。
                randomCode.append(strRand);
            }
            // 將四位數(shù)字的驗(yàn)證碼保存到Session中。
            code = randomCode.toString();
        }

        public void write(String path) throws IOException {
            OutputStream sos = new FileOutputStream(path);
            this.write(sos);
        }

        public void write(OutputStream sos) throws IOException {
            ImageIO.write(buffImg, "png", sos);
            sos.close();
        }

        public BufferedImage getBuffImg() {
            return buffImg;
        }

        public String getCode() {
    return code;
        }
    }

2.3 控制器使用驗(yàn)證碼 如 CodeController

    @RequestMapping("/getCode.do")
        public void getCode(HttpServletRequest reqeust, HttpServletResponse response) throws IOException {

            response.setContentType("image/jpeg");
            // 禁止圖像緩存。
            response.setHeader("Pragma", "no-cache");
            response.setHeader("Cache-Control", "no-cache");
            response.setDateHeader("Expires", 0);

            HttpSession session = reqeust.getSession();

            ValidateCode vCode = new ValidateCode(100, 28, 4, 100);
            session.setAttribute(Helper.SESSION_CHECKCODE, vCode.getCode());
            vCode.write(response.getOutputStream());
        }

3. 應(yīng)用
實(shí)現(xiàn)功能:前端AES加密傳輸后端解密以及n次輸入驗(yàn)證不通過后需要驗(yàn)證碼
有了上面的基礎(chǔ),實(shí)現(xiàn)起來應(yīng)該不難了。

3.1 login.html

    <input type="hidden" id="KEY" value="${Session.login_token}"/>
        <form action="signIn" method="post" id="loginForm">
          <div class="form-group has-feedback">
            <input type="text" class="form-control" placeholder="Email" name="username"
               onkeydown="javascript:if(event.keyCode==13) $('#password').focus();">
          </div>
          <div class="form-group has-feedback">
            <input type="password" class="form-control" id="password"
                id="formPwd" onkeydown="javascript:if(event.keyCode==13) login();" >
          </div>
          <#if Session.login_failure_count?? && (Session.login_failure_count <=0) >
          <div class="form-group has-feedback">
            <input name="checkCode" onkeydown="javascript:if(event.keyCode==13)  login();" type="text" id="checkCode" maxlength="4" onblur="checkTheCode(this)" style="120px;"/> 
            <img src="getCode.do" id="CreateCheckCode" align="middle" title="點(diǎn)擊刷新驗(yàn)證碼" onclick="getCode()"  style="cursor: pointer;">
            <span id="checkCodeSpan" style="float: right;color: red;"></span>
          </div>
          </#if>
          <div class="row">
            <div class="col-xs-8">
              <div class="checkbox icheck">
                <label>
                  <input type="checkbox" name="remember" checked="checked"  >記住密碼
                </label>
              </div>
            </div>
            <!-- /.col -->
            <div class="col-xs-4">
              <button type="button" onclick="login()"  class="btn btn-primary btn-block btn-flat">登錄</button>
            </div>
            <!-- /.col -->
          </div>
        </form>
     <script>
     function login(){
     $('#loginForm').form('submit',{
      onSubmit: function(param){
          var username = $('#loginForm input[name=username]').val();
          if($.trim(username)==''){
              alert('賬號(hào)不能為空!')
              $('#loginForm input[name=username]').focus();
              return false;
          }
          var p = $('#loginForm #password').val();
          if($.trim(p)==''){
              alert('密碼不能為空!')
              $('#loginForm #password').focus();
              return false;
          }
          var checkCodeInput = $('#loginForm #checkCode');
          if(checkCodeInput.length>0){//判斷元素是否存在
              var checkCode = checkCodeInput.val();
              if($.trim(checkCode)=='' || checkCode.length!=4 ){
                  alert('請(qǐng)輸入4位驗(yàn)證碼!')
                  checkCodeInput.select();
                  checkCodeInput.focus(); 
                  return false;
              }
          }
          var key = $('#KEY').val();
          key = CryptoJS.enc.Utf8.parse(key);  
          p = CryptoJS.enc.Utf8.parse($.trim(p)); 
          var encrypted = CryptoJS.AES.encrypt(p, key, {mode:CryptoJS.mode.ECB,padding: CryptoJS.pad.Pkcs7});
          param.password = encrypted.toString();
      },
      success:function(data){
          var data = eval('(' + data + ')');
          if (data.success){
              window.location.href = '${request.contextPath}/';
          }else{
              if(data.info=='timeout'){//可能已經(jīng)就登錄了,無需再次登錄
                  alert('登錄超時(shí)或已經(jīng)登錄!');
                  window.location.href = '${request.contextPath}/';
              }else if('checkCode'==data.info){//需要驗(yàn)證碼了
                  alert('用戶名或密碼錯(cuò)誤!');
                  window.location.href = 'login';
              }else if('codeError'==data.info){//驗(yàn)證碼錯(cuò)誤
                  getCode();
                  $('#checkCodeSpan').text('驗(yàn)證碼錯(cuò)誤');
                  $('#loginForm #checkCode').select();
                  $('#loginForm #checkCode').focus(); 
              }else{
                  //登錄失敗,更新login_token
                  $('#KEY').val(data.data);
                  if($('#checkCodeSpan')){
                      $('#checkCodeSpan').text('');
                  }
                  alert(data.info);
              }
          }
      }
     }) ;
    }

    function getCode(){
        $("#CreateCheckCode").attr('src',"getCode.do?nocache=" + new Date().getTime());  
    }
     </script>

3.2 Controller

在請(qǐng)求登錄頁面時(shí)需要后端生成一個(gè)隨機(jī)的16位字符串的key,用于前后端加密解密用,該key在登錄成功后銷毀,存儲(chǔ)在session中。

    @RequestMapping(value = "/login", method = RequestMethod.GET)
        public String login(){
            //生成login_token
            session.setAttribute(Helper.SESSION_LOGIN_TOKEN,RandomUtil.generateString(16));//登錄令牌,用于密碼加密的key,16位長(zhǎng)度
            if(session.getAttribute(Helper.SESSION_USER) == null){
                return "login";
            }
            else
                return "redirect:/";
        }

接下來是提交form表單的請(qǐng)求

    @RequestMapping(value = "/signIn", method = RequestMethod.POST,produces = "text/html;charset=UTF-8")
        @ResponseBody
        public String signIn(String username,String password,boolean remember,String checkCode) throws AuthorizationException{
            System.out.println(username+","+password+","+remember+","+checkCode);
            Object token = session.getAttribute(Helper.SESSION_LOGIN_TOKEN);//原始令牌

            if(token==null) return JSON.toJSONString(new Result(false,"timeout"));//登錄成功后token失效,則頁面失效,客戶端需要重定向到主界面
            Object countObj = session.getAttribute(Helper.SESSION_LOGIN_FAILURE_COUNT);
            int count = countObj==null?ConfigInfo.login_failure_count:Integer.parseInt(countObj.toString());
            System.out.println("剩余次數(shù):"+count);
            //驗(yàn)證碼邏輯
            if(count<=0){//需要驗(yàn)證碼
                Object oldCode = session.getAttribute(Helper.SESSION_CHECKCODE);
                if(checkCode==null||oldCode==null){//該登錄界面沒有驗(yàn)證碼字段,但是已經(jīng)消耗掉了剩余次數(shù),說明該頁面是過期頁面,需要重新登錄
                    return JSON.toJSONString(new Result(false,"timeout"));//客戶端需要重定向到主界面
                }
                if(checkCode.trim().isEmpty()) return JSON.toJSONString(new Result(false,"請(qǐng)輸入驗(yàn)證碼"));
                if(oldCode.toString().equalsIgnoreCase(checkCode)){
                    //驗(yàn)證通過,可信客戶端,給兩次剩余次數(shù)
                    count=2;
                    session.setAttribute(Helper.SESSION_LOGIN_FAILURE_COUNT,2);
                }else{
                    return JSON.toJSONString(new Result(false,"codeError"));//驗(yàn)證碼不正確,客戶端需要刷新驗(yàn)證碼
                }
            }
            //解密
            try {
                password = EncryptUtil.aesDecrypt(password,token.toString());//解密后
                System.out.println("Decrypt:"+password);
            } catch (Exception e) {
                e.printStackTrace();
                return JSON.toJSONString(new Result(false,"timeout"));//客戶端需要重定向到主界面
            }
            //登錄校驗(yàn)
            String key = RandomUtil.generateString(16);//重新生成登錄令牌,任何登錄失敗的操作都需要更新登錄令牌
            ViewSysUser user =  sysUserService.selectUserPwd(username,password);
            if(user == null){
                session.setAttribute(Helper.SESSION_LOGIN_TOKEN,key);
                session.setAttribute(Helper.SESSION_LOGIN_FAILURE_COUNT,--count);//剩余次數(shù)-1
                if(count<=0) return JSON.toJSONString(new Result(false,"checkCode"));//客戶端需要重定向到登錄界面將驗(yàn)證碼顯示出來
                return JSON.toJSONString(new Result(false,"用戶名或密碼錯(cuò)誤!",key));
            }else{
                if(user.getUserid()!=ConfigInfo.admin_id && !user.getuStatus().equals(ConfigInfo.user_status_normal)) {
                    session.setAttribute(Helper.SESSION_LOGIN_TOKEN,key);
                    return JSON.toJSONString(new Result(false,"登錄失敗,該賬號(hào)已被禁止使用!",key));
                }
                //登錄成功
                session.removeAttribute(Helper.SESSION_LOGIN_TOKEN);
                loginUser = user;
                session.setAttribute(Helper.SESSION_USER,loginUser);
                sysEventService.insertEventLog(Helper.logTypeSecurity,username+" 登錄系統(tǒng)");
                return JSON.toJSONString(new Result(true,"登錄成功!"));
            }
        }

下面是生成隨機(jī)數(shù)的工具類,很簡(jiǎn)單

    package com.jykj.demo.util;

    import java.util.Random;  

    public class RandomUtil {  
        public static final String ALLCHAR = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";  
        public static final String LETTERCHAR = "abcdefghijkllmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";  
        public static final String NUMBERCHAR = "0123456789";  

        /** 
         * 返回一個(gè)定長(zhǎng)的隨機(jī)字符串(只包含大小寫字母、數(shù)字) 
         *  
         * @param length 
         *            隨機(jī)字符串長(zhǎng)度 
         * @return 隨機(jī)字符串 
         */  
        public static String generateString(int length) {  
            StringBuffer sb = new StringBuffer();  
            Random random = new Random();  
            for (int i = 0; i < length; i++) {  
                sb.append(ALLCHAR.charAt(random.nextInt(ALLCHAR.length())));  
            }  
            return sb.toString();  
        }  

        /** 
         * 返回一個(gè)定長(zhǎng)的隨機(jī)純字母字符串(只包含大小寫字母) 
         *  
         * @param length 
         *            隨機(jī)字符串長(zhǎng)度 
         * @return 隨機(jī)字符串 
         */  
        public static String generateMixString(int length) {  
            StringBuffer sb = new StringBuffer();  
                    Random random = new Random();  
            for (int i = 0; i < length; i++) {  
                sb.append(LETTERCHAR.charAt(random.nextInt(LETTERCHAR.length())));  
            }  
            return sb.toString();  
        }  

        /** 
         * 返回一個(gè)定長(zhǎng)的隨機(jī)純大寫字母字符串(只包含大小寫字母) 
         *  
         * @param length 
         *            隨機(jī)字符串長(zhǎng)度 
         * @return 隨機(jī)字符串 
         */  
        public static String generateLowerString(int length) {  
            return generateMixString(length).toLowerCase();  
        }  
    
        /** 
         * 返回一個(gè)定長(zhǎng)的隨機(jī)純小寫字母字符串(只包含大小寫字母) 
         *  
         * @param length 
         *            隨機(jī)字符串長(zhǎng)度 
         * @return 隨機(jī)字符串 
         */  
        public static String generateUpperString(int length) {  
            return generateMixString(length).toUpperCase();  
        }  

        /** 
         * 生成一個(gè)定長(zhǎng)的純0字符串 
         *  
         * @param length 
         *            字符串長(zhǎng)度 
         * @return 純0字符串 
         */  
        public static String generateZeroString(int length) {  
            StringBuffer sb = new StringBuffer();  
            for (int i = 0; i < length; i++) {  
                sb.append('0');  
            }  
            return sb.toString();  
        }  

        /** 
         * 根據(jù)數(shù)字生成一個(gè)定長(zhǎng)的字符串,長(zhǎng)度不夠前面補(bǔ)0 
         *  
         * @param num 
         *            數(shù)字 
         * @param fixdlenth 
         *            字符串長(zhǎng)度 
         * @return 定長(zhǎng)的字符串 
         */  
        public static String toFixdLengthString(long num, int fixdlenth) {  
            StringBuffer sb = new StringBuffer();  
            String strNum = String.valueOf(num);  
            if (fixdlenth - strNum.length() >= 0) {  
                sb.append(generateZeroString(fixdlenth - strNum.length()));  
            } else {  
                throw new RuntimeException("將數(shù)字" + num + "轉(zhuǎn)化為長(zhǎng)度為" + fixdlenth  
                        + "的字符串發(fā)生異常!");  
            }  
            sb.append(strNum);  
            return sb.toString();  
        }  

        /** 
         * 每次生成的len位數(shù)都不相同 
         *  
         * @param param 
         * @return 定長(zhǎng)的數(shù)字 
         */  
        public static int getNotSimple(int[] param, int len) {  
            Random rand = new Random();  
            for (int i = param.length; i > 1; i--) {  
                int index = rand.nextInt(i);  
                int tmp = param[index];  
                param[index] = param[i - 1];  
                param[i - 1] = tmp;  
            }  
            int result = 0;  
            for (int i = 0; i < len; i++) {  
                result = result * 10 + param[i];  
            }  
            return result;  
        }          
    }  

3.4 實(shí)現(xiàn)思路

    現(xiàn)在淘寶登錄界面采用的是 無知識(shí)型驗(yàn)證碼,只需要拖動(dòng)滑塊來判斷是否是機(jī)器還是人,如果拖滑塊驗(yàn)證失敗,會(huì)彈出驗(yàn)證碼輸入或點(diǎn)擊選擇的框,來進(jìn)行二次驗(yàn)證。若驗(yàn)證成功后,連續(xù)5次輸入錯(cuò)誤的用戶名或密碼,則又會(huì)彈出驗(yàn)證碼來需要繼續(xù)驗(yàn)證。也就是說有一個(gè)風(fēng)險(xiǎn)分析系統(tǒng),如果滿 
    足一定的條件(如連續(xù)多次輸入錯(cuò)誤等)則需要加強(qiáng)驗(yàn)證。風(fēng)險(xiǎn)分析系統(tǒng)要綜合多種因素如ip,用戶信息等等。Google更簡(jiǎn)單,通過點(diǎn)擊復(fù)選框(I’m not a robot)就通過驗(yàn)證。

    剛開始時(shí)是不需要驗(yàn)證碼的,用session來存儲(chǔ)剩余次數(shù),當(dāng)連續(xù)5次驗(yàn)證都失敗后,該計(jì)數(shù)遞減為0,則后臺(tái)判斷該客戶端不是很可信,需要驗(yàn)證碼來加強(qiáng)驗(yàn)證,重新刷新登錄界面(可以重定向?qū)崿F(xiàn))把驗(yàn)證碼輸入框加載出來。客戶端需要同時(shí)提交賬號(hào)密碼以及驗(yàn)證碼到后臺(tái)驗(yàn)證,若驗(yàn)證碼通 
     過驗(yàn)證,重新將次數(shù)復(fù)位(或自定義設(shè)置),表示該客戶端暫時(shí)可信下次提交登錄時(shí)可以不需要驗(yàn)證碼。

    對(duì)于密碼的加密傳輸與后端解密,key的生成與銷毀的控制很關(guān)鍵。當(dāng)加載登錄頁面時(shí),由后臺(tái)生成一個(gè)key給該頁面,并保存到隱藏域中,同時(shí)該key也是存在session中。前端js用AES加密算法將密碼和key混合加密,提交給后臺(tái),后臺(tái)用相應(yīng)的解密算法還原出原始密碼,然后該原始密碼用存                
     儲(chǔ)時(shí)使用的多重混合加密算法進(jìn)行加密與數(shù)據(jù)庫中的密碼匹配驗(yàn)證。當(dāng)驗(yàn)證成功后,移除session中的key。而驗(yàn)證失敗后的邏輯很關(guān)鍵,驗(yàn)證失敗后,需要重新生成一個(gè)key給客戶端,所以客戶端通過返回的信息將key賦值到那個(gè)隱藏域字段中,這樣達(dá)到刷新key的目的。

    總體來說,驗(yàn)證碼的邏輯會(huì)有點(diǎn)復(fù)雜。驗(yàn)證碼的驗(yàn)證最好放到后臺(tái)來驗(yàn)證,如果放到前臺(tái)就需要用一個(gè)隱藏域字段來存這個(gè)驗(yàn)證碼,這樣的話機(jī)器也可以獲取到,那機(jī)器就不用識(shí)別圖片就可以驗(yàn)證了,這樣驗(yàn)證碼就失去了作用。

總結(jié)

以上是生活随笔為你收集整理的js加密后台加密解密以及验证码的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。