I recently discovered a very interesting thing, the points mall without logging in. After careful study and analysis, I came to the conclusion that no matter it is in the mall or anything else, you can play it without logging in. The principle is also very simple. The browser has a fingerprint ID, and the APP has a unique identifier of the device. In the end, I chose to use uni-app and laravel to write a login-free system.
1. uni-app
1.Install Fingerprint2
npm install --save fingerprintjs2
2. Install CryptoJS
npm install --save crypto-js
3. Complete global request encapsulation code
const base_url = 'https://xxx.com/api/' import Fingerprint2 from 'fingerprintjs2' import CryptoJS from 'crypto-js' const encrypt = (str) => {<!-- --> //Key 16 bits var key = CryptoJS.enc.Utf8.parse('Uy2LlvFGFGbgIH8a'); //Encrypted vector 16 bits 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 = {<!-- -->}) => {<!-- --> // Get the stored device ID let device = uni.getStorageSync('device') // Get the stored client type let client = uni.getStorageSync('client') // Get device information let app = uni.getSystemInfoSync() // #ifdef APP // Determine whether the device identifier is not present if (!device) {<!-- --> //Storage device identification uni.setStorageSync('device', app.deviceId) // Determine whether it is iOS if (app.platform == 'ios') {<!-- --> uni.setStorageSync('client', 'iOS') } // Determine whether it is Android if (app.platform == 'android') {<!-- --> uni.setStorageSync('client', 'Android') } } // #endif // #ifndefAPP // Get browser request headers const userAgent = navigator.userAgent.toLowerCase(); Fingerprint2.get(function(components) {<!-- --> const values = components.map(function(component, index) {<!-- --> if (index === 0) {<!-- --> //Replace UA's wifi or 4G network in the WeChat browser with empty, otherwise the ID will be different when switching networks return component.value.replace(/\bNetType\/\w + \b/, '') } return component.value }) //Storage unique identifier uni.setStorageSync('device', Fingerprint2.x64hash128(values.join(''), 31)) }); // Determine whether it is a mobile browser 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') } // Retrieve device identification device = uni.getStorageSync('device') // Re-obtain the client type client = uni.getStorageSync('client') // #endif // Submit encrypted device information to the background params.device = encrypt(JSON.stringify({<!-- --> //Unique identifier of the device device: device, //AppID of the application appId: app.appId, //The APP name of the application appName: app.appName, // Get the current timestamp time: Math.round(new Date().getTime() / 1000).toString() })); \t return new Promise((resolve, reject) => {<!-- --> uni.request({<!-- --> url: base_url + url, method: 'POST', data: params, success(response) {<!-- --> const res = response.data // Determine whether the request is successful if (res.code == 200) {<!-- --> resolve(res); } else {<!-- --> uni.showToast({<!-- --> title: res.msg, icon: 'none' }) } }, fail(err) {<!-- --> reject(err); }, complete() {<!-- -->} }); }).catch((e) => {<!-- -->}); };
2. laravel
Detect the complete code of login middleware
<?php namespace App\Http\Middleware; use App\Http\Controllers\Controller; //Introduce user model use App\Models\Member; use Carbon\Carbon; use Closure; use Illuminate\Http\Request; class CheckUser {<!-- --> public function handle(Request $request, Closure $next) {<!-- --> // Get logged in user information $member = auth('member')->user(); // If there is no logged in user information if (!$member) {<!-- --> // Determine whether device information is passed in if ($request->device) {<!-- --> //Decrypt device encoding $device = json_decode($this->decryptString($request->device), true); // Get the current timestamp $datetime1 = Carbon::createFromTimestamp(time()); // Get the passed timestamp $datetime2 = Carbon::createFromTimestamp($device['time']); // Use the diffInSeconds method to get the time difference between two times (in seconds) $timeDifference = $datetime1->diffInSeconds($datetime2); // Determine whether the device decryption is correct and the time difference is less than 10 seconds if (!isset($device['appId']) || !isset($device['device']) || !isset($device['appName']) || abs($timeDifference) >= 10) {<!-- --> return response()->json(['code' => 0, 'msg' => 'Don't think too much, just use it honestly']); } if ($device['appId'] != '__UNI__A88888888' || $device['appName'] != 'APP name') {<!-- --> return response()->json(['code' => 0, 'msg' => 'Don't think too much, just use it honestly']); } // Get user information of the device $member = Member::where('device', $device['device'])->orWhere('phone', $request->phone)->first(); // Determine whether the user does not exist if (!$member) {<!-- --> //Create a new user $member = Member::create([ // Generate random UID 'uid' => mt_rand(111111, 999999), // Get the user's mobile phone number 'phone' => $request->phone, // Get the superior ID 'parent' => $request->parent, // Get the unique identifier of the device 'device' => $device['device'] ]); } else {<!-- --> // Determine if the user's device is not equal to the requested device if ($member['device'] != $device['device']) {<!-- --> //Update device information $member = $member->update(['device' => $device['device']]); } } } } if (isset($member['uid'])) {<!-- --> $request->headers->set('uid', $member['uid']); } return $next($request); } //decryption function public function decryptString($str) {<!-- --> //Set the key $key = 'Uy2LlvFGFGbgIH8a'; //Set offset $iv = 'YdRrSPUrVlQ1UD4W'; // Return the decrypted string return openssl_decrypt(base64_decode($str), 'AES-128-CBC', $key, OPENSSL_RAW_DATA, $iv); } }
3. Summary
When encrypting, you can intersperse some other information to verify whether it is a legitimate request. Basically, each line of code has comments written for your reference.