当前位置: 首页 > 后端技术 > Java

Java二维码登录流程实现(包括短地址生成,包括部分代码)

时间:2023-04-01 18:16:50 Java

近年来,二维码的使用越来越流行。登录网站这个工作,所以我研究了这套机制,用代码实现了整个过程,接下来我就和大家说说二维码登录那些东西。二维码的原理二维码是由微信创建的。当我们扫描二维码登录微信时,感觉很神奇。但是,我们了解它的原理,并没有那么神奇。二维码实际上是通过黑白点阵包含一个url请求信息。终端扫码,请求url,进行相应操作。一般扫码操作的原理和微信登录、支付宝扫码支付原理是一样的:如图:1.请求二维码桌面端向服务器端发起请求获取二维码。2.生成具有唯一标识的二维码。桌面会随机生成一个id,唯一标识二维码,用于后续操作。3、手机端扫描二维码,解码二维码中的url请求。4、移动终端向服务器发送请求。移动终端向服务器发送url请求。请求包含两条信息,唯一的id标识扫描了哪个代码,终端上浏览器中的特定cookie或header参数将标识扫描了哪个用户。5、服务器提示扫码成功。当服务器收到对二维码中信息的url请求时,通知终端已经成功扫码并添加了必要的登录cookies等信息。这里一般有几种通知方式:websocket,轮训holdrequestuntiltimeout,每隔几秒轮训。二维码中url的艺术如何实现自己客户端和其他客户端(比如微信)的区别?例如,在业务中,您可能想要这样的操作。应用程序(如微信)扫描时,如果要跳转到提示页面,提示页面可以有该应用程序的下载链接;自己的app扫描时,可以直接发出相应的请求。在这种情况下,可以这样做,将二维码中的所有链接都先加密一层,再统一处理另一层链接。例如:www.test.com/qr?p=xxxxxx,p参数包含服务端和客户端约定的加解密算法(可以是对称的也可以是非对称的),当终端扫码到这个具体path,直接用解密算法解出p参数,得到www.testqr.com/qrcode?key=s1arV,这样就可以向服务端发起请求了,因为其他客户端不知道这个规则,所以可以只直接请求www.test。com/qr?p=xxxxxx,这个请求返回提示页面。如何让二维码更简单很多时候,既要让马跑起来,又要让马不吃草。想要二维码包含很多参数,又不想二维码太复杂扫不出来。这时候就需要考虑如何在不影响业务的情况下,让二维码变得简单。与终端约定的规则:比如定义编码信息中的i??参数为1、2、3表示不同的uri,当终端匹配不同的i参数时,请求哪个接口简化所有可以简化的:简化uri,简化参数key,value。比如www.a.com/q?k=s1arV比www.abc.def.adfg.edu.com.cn/qrcode/scan?k=77179574e98a7c860007df62a5dbd98b简单很多,生成的二维码也更容易扫描.简化uniqueid参数:上篇请求中的参数值只有5位,后面请求中的参数值为生成的32位md5值。为一端生成密钥至关重要。示例代码生成二维码(去掉白边,增加中间的logo)需要导入jar包:zxing的core-2.0.jarimportjava.awt.BasicStroke;importjava.awt.Color;importjava.awt.Graphics;importjava.awt.Graphics2D;导入java.awt.Image;导入java.awt.Shape;导入java.awt.geom.RoundRectangle2D;导入java.awt.image.BufferedImage;导入java.io.ByteArrayOutputStream;导入java.io.FileOutputStream;导入java.io.IOException;导入java.util.HashMap;导入java.util.Map;导入javax.imageio.ImageIO;导入com.google.zxing.BarcodeFormat;导入com.google.zxing.EncodeHintType;导入com.google.zxing.MultiFormatWriter;导入com.google.zxing.common.BitMatrix;导入com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;公共类QrCodeUtil{privatestaticfinalintBLACK=Color.black.getRGB();privatestaticfinalintWHITE=Color.WHITE.getRGB();privatestaticfinalintDEFAULT_QR_SIZE=183;私有静态最终字符串DEFAULT_QR_FORMAT="png";私有静态最终字节[]EMPTY_BYTES=新字节[0];publicstaticbyte[]createQrCode(Stringcontent,intsize,Stringextension){returncreateQrCode(content,size,extension,null);}}/***生成带图片的二维码*@paramcontent二维码要包含的信息*@paramsize大小*@paramextension文件格式扩展名*@paraminsertImg中间的Logo图片*@return*/publicstaticbyte[]createQrCode(Stringcontent,intsize,Stringextension,ImageinsertImg){if(size<=0){thrownewIllegalArgumentException("size("+size+")cannotbe<=0");}ByteArrayOutputStreambaos=null;尝试{Maphints=newHashMap();hints.put(EncodeHintType.CHARACTER_SET,"utf-8");hints.put(EncodeHintType.ERROR_CORRECTION,ErrorCorrectionLevel.M);//使用信息生成指定大小的位矩阵BitMatrixm=newMultiFormatWriter().encode(content,BarcodeFormat.QR_CODE,size,size,hints);//去除白边m=updateBit(m,0);intwidth=m.getWidth();intheight=m.getHeight();//将BitMatrix中的信息设置到BufferdImage中,组成黑白图像BufferedImageimage=newBufferedImage(width,height,BufferedImage.TYPE_INT_RGB);for(inti=0;i大小/6?尺寸/6:宽度;//logo设置为二维码的六分之一大小height=height>size/6?大小/6:高度;Graphics2D图=source.createGraphics();intx=(大小-宽度)/2;inty=(尺寸-高度)/2;graph.drawImage(insertImg,x,y,width,height,null);形状shape=newRoundRectangle2D.Float(x,y,width,width,6,6);graph.setStroke(newBasicStroke(3f));graph.draw(形状);图.dispose();}catch(Exceptione){e.printStackTrace();}}publicstaticbyte[]createQrCode(Stringcontent){returncreateQrCode(content,DEFAULT_QR_SIZE,DEFAULT_QR_FORMAT);}publicstaticvoidmain(String[]args){try{FileOutputStreamfos=newFileOutputStream("ab.png");fos.write(createQrCode("test"));fos.close();}catch(Exceptione){//TODO自动生成的catch块e.printStackTrace();}}}生成短链接的基本思想:短网址映射算法理论:给长网址加上随机数,使用md5算法生成一个32位的签名串,分为4段,每段有8个字符,4段循环处理。取每一段的8个字符,把它当做一个十六进制字符串和0x3fffffff(30-bit1)位AND运算,忽略30多位处理将每段得到的30位数字分成6段,每段5-digit数字用作字母表的索引提取特定字符,依次得到6位字符串;这样一个md5字符串可以得到4个6位数字的字符串,其中任意一个都可以作为这个长url的短url地址最好用key-value数据库存储,万一发生碰撞,就改成一个,如果四个都碰撞了,重新生成md5(因为有随机数,会生成不同的md5)publicclassShortUrlUtil{/***passEnter32-bitmd5value*@parammd5*@return*/publicstaticString[]shortUrl(Stringmd5){//String[]chars=newString[]{"a","b"用于生成URL,"c","d","e","f","g","h","i","j","k","l","m","n",“o”、“p”、“q”、“r”、“s”、“t”、“u”、“v”、“w”、“x”、“y”、“z”、“0”","1","2","3","4","5","6","7","8","9","A","B","C",“D”、“E”、“F”、“G”、"H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z"};String[]resUrl=newString[4];for(inti=0;i<4;i++){//加密字符按照8位十六进制和0x3FFFFFFF进行位与运算,超过30位的忽略StringsTempSubString=md5.substring(i*8,i*8+8);//这里需要使用long类型进行转换,因为Inteper.parseInt()只能处理31位,第一位是符号位,如果不使用long会越界longlHexLong=0x3FFFFFFF&Long.parseLong(sTempSubString,16);StringoutChars="";for(intj=0;j<6;j++){//将得到的值与0x0000003D按位与运算得到字符数组charsindexlongindex=0x0000003D&lHexLong;//添加获取的字符outChars+=chars[(int)索引];//每个周期右移5位lHexLong=lHexLong>>5;}//将字符串存储到对应索引的输出数组中resUrl[i]=outChars;}返回resUrl;}publicstaticvoidmain(String[]args){String[]test=shortUrl("fdf8d941f23680be79af83f921b107ac");for(Stringstring:test){System.out.println(string);}}}有谁想要转载我的文章,不用联系我,转载后请把链接私信给我,谢谢!