uni-app结合laravel实现免登陆

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

一、uni-app

1.安装Fingerprint2

npm install --save fingerprintjs2

2.安装CryptoJS

npm install --save crypto-js

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

js 复制代码
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) => {});
};

二、laravel

检测登录中间件完整代码

php 复制代码
<?php

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);
    }
}

三、总结

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

相关推荐
qq_390161771 分钟前
防抖函数--应用场景及示例
前端·javascript
3345543229 分钟前
element动态表头合并表格
开发语言·javascript·ecmascript
John.liu_Test31 分钟前
js下载excel示例demo
前端·javascript·excel
南宫生41 分钟前
贪心算法习题其四【力扣】【算法学习day.21】
学习·算法·leetcode·链表·贪心算法
Yaml444 分钟前
智能化健身房管理:Spring Boot与Vue的创新解决方案
前端·spring boot·后端·mysql·vue·健身房管理
PleaSure乐事1 小时前
【React.js】AntDesignPro左侧菜单栏栏目名称不显示的解决方案
前端·javascript·react.js·前端框架·webstorm·antdesignpro
残月只会敲键盘1 小时前
面相小白的php反序列化漏洞原理剖析
开发语言·php
哟哟耶耶1 小时前
js-将JavaScript对象或值转换为JSON字符串 JSON.stringify(this.SelectDataListCourse)
前端·javascript·json
getaxiosluo1 小时前
react jsx基本语法,脚手架,父子传参,refs等详解
前端·vue.js·react.js·前端框架·hook·jsx
ac-er88881 小时前
PHP弱类型安全问题
开发语言·安全·php