• uni-app结合laravel实现免登陆


    最近发现一个挺好玩的东西,免登陆积分商城,仔细研究分析后得出结论,无论是商城还是其他,免登录都可以玩玩的。原理也很简单,浏览器都有指纹ID,APP有设备唯一标识,最终选择使用uni-app与laravel写了个免登陆系统。

    一、uni-app

    1.安装Fingerprint2

    npm install --save fingerprintjs2
    
    • 1

    2.安装CryptoJS

    npm install --save crypto-js
    
    • 1

    3.完整的全局请求封装代码

    const base_url = 'https://xxx.com/api/'
    import Fingerprint2 from 'fingerprintjs2'
    import CryptoJS from 'crypto-js'
    
    const encrypt = (str) => {
    	//密钥16位
    	var key = CryptoJS.enc.Utf8.parse('Uy2LlvFGFGbgIH8a');
    	//加密向量16位
    	var iv = CryptoJS.enc.Utf8.parse('YdRrSPUrVlQ1UD4W');
    	var encrypted = CryptoJS.AES.encrypt(str, key, {
    		iv: iv,
    		mode: CryptoJS.mode.CBC,
    		padding: CryptoJS.pad.Pkcs7
    	});
    	return encrypted.toString();
    }
    
    export default (url, params = {}) => {
    	// 获取存储的设备标识
    	let device = uni.getStorageSync('device')
    	// 获取存储的客户端类型
    	let client = uni.getStorageSync('client')
    	// 获取设备信息
    	let app = uni.getSystemInfoSync()
    
    	// #ifdef APP
    	// 判断设备标识是否不在
    	if (!device) {
    		// 存储设备标识
    		uni.setStorageSync('device', app.deviceId)
    		// 判断是否为iOS
    		if (app.platform == 'ios') {
    			uni.setStorageSync('client', 'iOS')
    		}
    		// 判断是否为Android
    		if (app.platform == 'android') {
    			uni.setStorageSync('client', 'Android')
    		}
    	}
    	// #endif
    
    	// #ifndef APP
    	// 获取浏览器请求头
    	const userAgent = navigator.userAgent.toLowerCase();
    	Fingerprint2.get(function(components) {
    		const values = components.map(function(component, index) {
    			if (index === 0) {
    				//把微信浏览器里UA的wifi或4G等网络替换成空,不然切换网络会ID不一样
    				return component.value.replace(/\bNetType\/\w+\b/, '')
    			}
    			return component.value
    		})
    		// 存储唯一标识
    		uni.setStorageSync('device', Fingerprint2.x64hash128(values.join(''), 31))
    	});
    	// 判断是否为手机浏览器
    	if (/ipad|iphone|midp|rv:1.2.3.4|ucweb|android|windows ce|windows mobile/.test(userAgent)) {
    		uni.setStorageSync('client', 'wap')
    	} else {
    		uni.setStorageSync('client', 'web')
    	}
    	// 重新获取设备标识
    	device = uni.getStorageSync('device')
    	// 重新获取客户端类型
    	client = uni.getStorageSync('client')
    	// #endif
    
    	// 加密设备信息提交到后台
    	params.device = encrypt(JSON.stringify({
    		// 设备唯一标识
    		device: device,
    		// 应用的AppID
    		appId: app.appId,
    		// 应用的APP名称
    		appName: app.appName,
    		// 获取当前时间戳
    		time: Math.round(new Date().getTime() / 1000).toString()
    	}));
    	
    	return new Promise((resolve, reject) => {
    		uni.request({
    			url: base_url + url,
    			method: 'POST',
    			data: params,
    			success(response) {
    				const res = response.data
    				// 判断请求是否成功
    				if (res.code == 200) {
    					resolve(res);
    				} else {
    					uni.showToast({
    						title: res.msg,
    						icon: 'none'
    					})
    				}
    			},
    			fail(err) {
    				reject(err);
    			},
    			complete() {}
    		});
    	}).catch((e) => {});
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103

    二、laravel

    检测登录中间件完整代码

    
    
    namespace App\Http\Middleware;
    
    use App\Http\Controllers\Controller;
    // 引入用户模型
    use App\Models\Member;
    use Carbon\Carbon;
    use Closure;
    use Illuminate\Http\Request;
    
    class CheckUser
    {
        public function handle(Request $request, Closure $next)
        {
        	// 获取登录的用户信息
            $member = auth('member')->user();
            // 如果没有登录的用户信息
            if (!$member) {
                // 判断是否传入设备信息
                if ($request->device) {
                    // 解密设备编码
                    $device = json_decode($this->decryptString($request->device), true);
                    // 获取当前时间戳
                    $datetime1 = Carbon::createFromTimestamp(time());
                    // 获取传过来的时间戳
                    $datetime2 = Carbon::createFromTimestamp($device['time']);
                    // 使用diffInSeconds方法获取两个时间的时间差(以秒为单位)
                    $timeDifference = $datetime1->diffInSeconds($datetime2);
                    // 判断设备解密是否正确以及时间差小于10秒
                    if (!isset($device['appId']) || !isset($device['device']) || !isset($device['appName']) || abs($timeDifference) >= 10) {
                        return response()->json(['code' => 0, 'msg' => '别想太多,老老实实使用']);
                    }
                    if ($device['appId'] != '__UNI__A88888888' || $device['appName'] != 'APP名称') {
                        return response()->json(['code' => 0, 'msg' => '别想太多,老老实实使用']);
                    }
                    // 获取设备的用户信息
                    $member = Member::where('device', $device['device'])->orWhere('phone', $request->phone)->first();
                    // 判断用户是否不存在
                    if (!$member) {
                        // 创建一个新的用户
                        $member = Member::create([
                        	// 生成随机UID
                            'uid' => mt_rand(111111, 999999),
                            // 获取用户手机号
                            'phone' => $request->phone,
                            // 获取上级ID
                            'parent' => $request->parent,
                            // 获取设备唯一标识
                            'device' => $device['device']
                        ]);
                    } else {
                        // 判断用户的设备不等于请求的设备
                        if ($member['device'] != $device['device']) {
                            // 更新设备信息
                            $member = $member->update(['device' => $device['device']]);
                        }
                    }
                }
            }
            if (isset($member['uid'])) {
                $request->headers->set('uid', $member['uid']);
            }
            return $next($request);
        }
    
        // 解密函数
        public function decryptString($str)
        {
            // 设置密钥
            $key = 'Uy2LlvFGFGbgIH8a';
            // 设置偏移量
            $iv = 'YdRrSPUrVlQ1UD4W';
            // 返回解密后的字符串
            return openssl_decrypt(base64_decode($str), 'AES-128-CBC', $key, OPENSSL_RAW_DATA, $iv);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77

    三、总结

    加密的时候可以自行穿插一些其他信息来验证是否为合法请求,具体基本上每行代码都写了注释,供大家参考。

  • 相关阅读:
    Linux - Shell、Console和Terminal的区别
    快来试试!免费用上GPT-4 !!!
    什么是机器学习力场
    springboot读取resources下文件方式
    C#面向对象程序设计课程实验二: 实验名称:Windows 窗体程序
    golang入门笔记——nginx
    阿里巴巴Java开发编程规约(整理详细版)
    centos安装nacos
    5分钟搞懂Web3架构
    C++对引用和指针的理解、应用
  • 原文地址:https://blog.csdn.net/qq_36901092/article/details/133940514