uniapp小程序laravel+jwt权限认证完整系列

H-Chat:jwt登录验证实现 之前从网上照着视频敲过jwt,说实话敲得时候我都是一头雾水,但当时只想出效果,并没有深入了解,最近受于疫情的影响,动手实现一个APP,基于uniapp,取名叫H-Chat,其中用户认证模块自然用到token,于是翻了翻之前模仿的那个代码,结合网上搜索的结果,对json web token(jwt)有了更进一步的了解。 下面是典型的token认证方式: 1.客户端登录时通过账号和密码到服务端进行认证... 阅读详情

环境说明

uni-app
laravel 5.7 + jwt-auth 1.0.0

权限认证整体说明

  1. 设计表结构
  2. 前端 request 类
  3. 有关权限认证的 js 封装 包含无感知刷新 token
  4. laravel auth 中间件 包含无感知刷新 token
  5. 获取手机号登陆
  6. 无痛刷新 access_token 思路
  7. 小程序如何判断登陆状态

设计表结构

和一般设计表没有什么区别,如果是多平台小程序,通过 account_id 关联联合表。

CREATE TABLE `users` (
  `u_id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '账号id',
  `u_username` varchar(15) NOT NULL DEFAULT '' COMMENT '手机号隐藏 ',
  `u_nickname` varchar(15) NOT NULL COMMENT '分配用户名',
  `u_headimg` varchar(200) DEFAULT NULL COMMENT '头像',
  `u_province` varchar(50) DEFAULT NULL,
  `u_city` varchar(50) DEFAULT NULL,
  `u_platform` varchar(30) NOT NULL COMMENT '平台:小程序wx,bd等',
  `u_mobile` char(11) NOT NULL COMMENT '手机号必须授权',
  `u_openid` varchar(100) DEFAULT NULL COMMENT 'openid',
  `u_regtime` timestamp NULL DEFAULT NULL COMMENT '注册时间',
  `u_login_time` timestamp NULL DEFAULT NULL COMMENT '最后登陆时间',
  `u_status` tinyint(3) unsigned NOT NULL DEFAULT '1' COMMENT '0禁用1正常',
  `account_id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '平台联合id',
  PRIMARY KEY (`u_id`),
  KEY `platform` (`u_platform`,`u_mobile`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8mb4;

2. 前端 request 类

一个较不错的 request 类 luch-request ,支持动态修改配置、拦截器,在 uni-app 插件市场可以找到。
在这里插入图片描述
其中 request.js 不需要更改。自定义逻辑在 index.js。
index.js

import Request from './request';
import jwt from '@/utils/auth/jwt.js'; // jwt 管理 见下文

const http = new Request();
const baseUrl = 'http://xxx'; // api 地址

var platform = ''; // 登陆时需知道来自哪个平台的小程序用户
// #ifdef MP-BAIDU
platform = 'MP-BAIDU';
// #endif

/* 设置全局配置 */
http.setConfig((config) => { 
  config.baseUrl = baseUrl; //设置 api 地址
  config.header = {
    ...config.header
  }
  return config
})

/* 请求之前拦截器 */
http.interceptor.request((config, cancel) => {
	if (!platform) {cancel('缺少平台参数');}
	config.header = {
		...config.header,
		platform:platform
	} 
  if (config.custom.auth) {
  	// 需要权限认证的路由 需携带自定义参数 {custom: {auth: true}}
    config.header.Authorization = jwt.getAccessToken();
  }
  return config
})

http.interceptor.response(async (response) => { /* 请求之后拦截器 */
	console.log(response);
	// 如果是需要权限认证的路由
	if(response.config.custom.auth){
		if (response.data.code !== 0)
		{
			if(response.data.code == 4011){
				// 刷新 token
				jwt.setAccessToken(response.data.data.access_token);
				// 携带新 token 重新请求
				let repeatRes = await http.request(response.config);
				if ( repeatRes ) {
					response = repeatRes;
				}
			}else if(response.data.code == 401){
				// 登陆态失效则清除token:没有携带token、token无法再刷新
				jwt.clearAccessToken();
				jwt.clearUser();
			}
		}
	}
	return response

}, (response) => { // 请求错误做点什么
  return response
})

export {
  http
}

全局挂载

import Vue from 'vue'
import App from './App'

import { http } from '@/utils/luch/index.js' //这里
Vue.prototype.$http = http

Vue.config.productionTip = false
App.mpType = 'app'
const app = new Vue({
    ...App
})
app.$mount()

3.有关权限认证的 js 封装

authorize.js

篇幅原因,没有贴完整的代码,其他并没有使用到。比如 uni.checkSession(),由于使用 jwt 接管了小程序的登陆态,所以目前没有用到这个方法。

// #ifndef H5
const loginCode = provider => {
    return new Promise((resolve, reject) => {
        uni.login({
            provider: provider,
            success: function(loginRes) {
                if (loginRes && loginRes.code) { resolve(loginRes.code) } else { reject("获取code失败") }
            },
			fail:function(){ reject("获取code失败")}
        });
    })
}
// #endif
export {
	loginCode //登录获取code
}

jwt.js

专门管理 access_token 的,代码不多,同时将 userinfo 的管理也放在里面。

const tokenKey = 'accessToken';//键值
const userKey	= 'user'; // 用户信息

// token
const getAccessToken = function(){
	let token='';
	try {token = 'Bearer '+ uni.getStorageSync(tokenKey);} catch (e) {}
	return token;
}
const setAccessToken = (access_token) => {
	try {uni.setStorageSync(tokenKey, access_token);return true;} catch (e) {return false;}
}
const clearAccessToken = function(){
	try {uni.removeStorageSync(tokenKey);} catch (e) {}
}

// userinfo
const setUser = (user)=>{
	try {uni.setStorageSync(userKey, user);return true;} catch (e) {return false;}
}
const getUser = function(){
	try {return uni.getStorageSync(userKey)} catch (e) {return false;}
}
const clearUser = function(){
	try {uni.removeStorageSync(userKey)} catch (e) {}
}

export default {
  getAccessToken,setAccessToken,clearAccessToken,setUser,clearUser
}

auth.js

只处理 login ,为什么单独放在一个文件,没别的,因为到处都用到

import {loginCode} from '@/utils/auth/authorize.js';
import jwt from '@/utils/auth/jwt.js';
import {http} from '@/utils/luch/index.js';

const login=function(detail){
	return new Promise((resolve, reject) => {
		loginCode().then(code=>{
			detail.code = code;
			return http.post('/v1/auth/login',detail);
		})
		.then(res=>{
			jwt.setAccessToken(res.data.data.access_token);
			jwt.setUser(res.data.data.user);
			resolve(res.data.data.user);
		})
		.catch(err=>{
			reject('登陆失败')
		})
	})
}

export default {login}

4. laravel auth 中间件

这里叨叨一点 jwt-auth 方面的。1,当一个token过期并进行了刷新token,那么原token会被列在“黑名单”,即失效了。实际上 jwt-auth 也维护了一个文件来储存黑名单,而达到刷新时间上限才会清理失效的token。例如过期时间为10分钟,刷新上限为一个月,这期间会产生大量的黑名单,影响性能,所以尽量的调整,比如过期时间为60分钟,刷新上限为两周,或者过期时间一周,刷新上限一个月都没有问题的。2,关于无痛刷新方案,当token过期时,我采用的前端两次请求完成刷新,其中用户是无感知的,网上有直接一次请求自动刷新并登陆的方案,我没有采用,至于为什么,没别的,看不懂。不过我整理了各种 jwt 各种 exception ,需要的同学可以自定义。TokenExpiredException 过期、TokenInvalidException 无法解析令牌、UnauthorizedHttpException 未携带令牌、JWTException 令牌失效或者达到刷新上限或jwt内部错误。

<?php
namespace App\Http\Middleware;

use App\Library\Y;
use Closure;
use Exception;
use Tymon\JWTAuth\Exceptions\JWTException;
use Tymon\JWTAuth\Http\Middleware\BaseMiddleware;
use Tymon\JWTAuth\Exceptions\TokenExpiredException;

class ApiAuth extends BaseMiddleware
{

    public function handle($request, Closure $next, $guard = 'api')
    {
        // 在排除名单中 比如登录
        if($request->is(...$this->except)){
            return $next($request);
        }

        try {
            $this->checkForToken($request);// 是否携带令牌
            if ( $this->auth->parseToken()->authenticate() ) {
                return $next($request); //验证通过
            }
        }catch(Exception $e){
        	// 如果token 过期
            if ($e instanceof TokenExpiredException) {
                try{
                	// 尝试刷新 如果成功 返给前端 关于前端如何处理的 看前边 index.js
                    $token = $this->auth->refresh();
                    return Y::json(4011, $e->getMessage(),['access_token'=>$token]);
                }catch(JWTException $e){
                	// 达到刷新时间上限
                    return Y::json(401, $e->getMessage());
                }
            }else{
            	// 其他各种 直接返回 401 不再细分
                return Y::json(401, $e->getMessage());
            }
        }
    }

    protected $except = [
        'v1/auth/login',
    ];
}

5. 获取手机号登陆

<template>
	<view>
		<button type="default" open-type="getPhoneNumber" @getphonenumber="decryptPhoneNumber">获取手机号</button>
		<button @tap="me">获取用户数据</button>
		<button @tap="clear">清除用户数据</button>
	</view>
</template>

<script>
	import auth from '@/utils/auth/auth.js';
	import jwt from '@/utils/auth/jwt.js';
	var _self;
	export default{
		data() {return {}},
		onLoad(option) {},
		onShow(){},
		methods: {
			decryptPhoneNumber: function(e){
				// console.log(e.detail);
				if( e.detail.errMsg == "getPhoneNumber:ok" ){ //成功
					auth.login(e.detail);
				}
			},
			me: function(){
				_self.$http.get('/v1/auth/me',{custom: {auth: true}}).then(res=>{
					console.log(res,'success')
				}).catch(err=>{
					console.log(err,'error60')
				})
			},
			clear: function(){
				jwt.clearAccessToken();
				jwt.clearUser();
				uni.showToast({
					icon: 'success',
					title: '清除成功',
					duration:2000,
				});
			}
		},
		components: {}
	}
</script>

<style>
</style>

后端

// 登陆
    public function login(Request $request)
    {
        $platform = $request->header('platform');
        if(!$platform || !in_array($platform,User::$platforms)){
            return Y::json(1001, '不支持的平台类型');
        }
        $post = $request->only(['encryptedData', 'iv', 'code']);
        $validator = Validator::make($post, [
            'encryptedData' => 'required',
            'iv'            => 'required',
            'code'          => 'required'
        ]);
        if ($validator->fails()) {return Y::json(1002,'非法请求');}
        switch ($platform) {
            case 'MP-BAIDU':
                $decryption = (new BdDataDecrypt())->decrypt($post['encryptedData'],$post['iv'],$post['code']);
                break;
            default:
                $decryption = false;
                break;
        }
        // var_dump($decryption);
        if($decryption !== false){
            $user = User::where('u_platform',$platform)->where('u_mobile',$decryption['mobile'])->first();
            if($user){
                $user->u_login_time = date('Y-m-d H:i:s',time());
                $user->save();
            }else{
                $user = User::create([
                    'u_username'=> substr_replace($decryption['mobile'],'******',3,6),
                    'u_nickname'=> User::crateNickName(),
                    'u_platform'=> $platform,
                    'u_mobile'   => $decryption['mobile'],
                    'u_openid'  => $decryption['openid'],
                    'u_regtime' => date('Y-m-d H:i:s',time())
                ]);
            }
            
            $token = auth()->login($user);
            return Y::json(
                array_merge(
                    $this->respondWithToken($token),
                    ['user'=>['nickName'=>$user->u_nickname]]
                )
            );
        }
        return Y::json(1003,'登录失败'); 
    }
    // 返回 token
    protected function respondWithToken($token)
    {
        return ['access_token' => $token];
    }

手机号码解密

<?php
namespace App\Library;
use App\Library\Y;
class BdDataDecrypt
{

    private $_appid;
    private $_app_key;
    private $_secret;
	private $_session_key;
    
    public function __construct()
	{
        $this->_appid       = env('BD_APPID');
        $this->_app_key     = env('BAIDU_KEY');
		$this->_secret      = env('BD_SECRET');
    }

    public function decrypt($encryptedData, $iv, $code){
        $res = $this->getSessionKey($code);
        if($res === false){return false;}
        $data['openid'] = $res['openid'];
        $res = $this->handle($encryptedData,$iv,$this->_app_key,$res['session_key']);
        if($res === false){return false;}
        $res = json_decode($res,true);
        $data['mobile'] = $res['mobile'];
        return $data;
        
    }
    
    public function getSessionKey($code)
	{
		$params['code'] 		= $code;
		$params['client_id'] 	= $this->_app_key;
		$params['sk'] 			= $this->_secret;
        $res = Y::curl("https://spapi.baidu.com/oauth/jscode2sessionkey",$params,0,1);
        // var_dump($res);
        /**
         * 错误返回
         * array(3) {
            ["errno"]=>
            int(1104)
            ["error"]=>
            string(33) "invalid code , expired or revoked"
            ["error_description"]=>
            string(33) "invalid code , expired or revoked"
            }
            成功返回:
            array(2) {
                ["openid"]=>
                string(26) "z45QjEfvkUJFwYlVcpjwST5G8w"
                ["session_key"]=>
                string(32) "51b9297ababbcf43c1a099256bf82d75"
            }
         */
        if( isset($res['error']) ){
            return false;
        }
        return $res;
	}

    /**
     * 官方 demo
     * return string(24) "{"mobile":"18288881111"}" or false
     */
    private function handle($ciphertext, $iv, $app_key, $session_key)
    {
        $session_key = base64_decode($session_key);
        $iv = base64_decode($iv);
        $ciphertext = base64_decode($ciphertext);
    
        $plaintext = false;
        if (function_exists("openssl_decrypt")) {
            $plaintext = openssl_decrypt($ciphertext, "AES-192-CBC", $session_key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $iv);
        } else {
            $td = mcrypt_module_open(MCRYPT_RIJNDAEL_128, null, MCRYPT_MODE_CBC, null);
            mcrypt_generic_init($td, $session_key, $iv);
            $plaintext = mdecrypt_generic($td, $ciphertext);
            mcrypt_generic_deinit($td);
            mcrypt_module_close($td);
        }
        if ($plaintext == false) {
            return false;
        }
        // trim pkcs#7 padding
        $pad = ord(substr($plaintext, -1));
        $pad = ($pad < 1 || $pad > 32) ? 0 : $pad;
        $plaintext = substr($plaintext, 0, strlen($plaintext) - $pad);
        $plaintext = substr($plaintext, 16);
        $unpack = unpack("Nlen/", substr($plaintext, 0, 4));
        $content = substr($plaintext, 4, $unpack['len']);
        $app_key_decode = substr($plaintext, $unpack['len'] + 4);
        return $app_key == $app_key_decode ? $content : false;
    }
}

6. 无痛刷新 access_token 思路

先说我使用的方法是,后端判断 token 过期后,自动尝试刷新,刷新成功返回新的 token,前端在响应拦截器里,捕获到后端响应的约定 code,把新的 token 存储,并且紧接着二次请求,最终感知上是一次正常的请求。
另外一种思路,后端尝试刷新成功后,自动为当前用户登陆,并在 header 中返回新 token,前端只负责存储。

7. 小程序如何判断登陆状态

其实思路也很简单,非前后端分离怎么做的,前后端分离就怎么做,原理一样。非前后端分离,在每次请求时都会读取 session ,那么前后端分离,更好一些,有些公开请求不走中间件,也就无需判断登陆态,只有在需要权限认证的页面,在页面初始化时发出一次请求走中间件,以此判断登陆状态。
定义全局登陆检查函数

import jwt from '@/utils/auth/jwt.js';
Vue.prototype.checkLogin = function(){
	var TOKEN  = jwt.getAccessToken();
	return new Promise((resolve, reject) => {
		if(TOKEN){
			http.get('/v1/auth/check',{custom: {auth: true}}).then(res=>{
				// 走中间件 正常的响应只有三种状态码 未登陆返回 401未登陆 或者 4011 刷新token 其他自定义状态码一定是登陆态
				if(res.data.code == 401){
					resolve(false);return;
				}
				resolve(true);
			}).catch(err=>{
				resolve(false);
				console.log(err) // 这里是后端500错误或者网络不好
			})
		}else{
			resolve(false) //没有token 一定是未登陆
		}
	})
}

前端

<script>
	export default {
		data() {
			return {
				isLogin:null
			}
		},
		onLoad() {
			this.checkLogin().then(loginStatus=>{
				this.isLogin = loginStatus;
			});
		},
		methods: {
		},
		components: {}
	}
</script>
uniapp微信小程序基于uniCloud数据库,一套完整的授权登陆,生成token 1. 创建uniapp的uniCloud数据库,绑定云数据库。参考https://uniapp.dcloud.io/uniCloud/concepts/space。 绑定之后再uniCloud控制台查看管理。 2. uniapp微信小程序中授权的登陆。 2.1 创建tool.js文件: export default{ getTokenValue(options) { //1.获取用户的token let { success, fail, complete... 阅读详情

相关推荐

AIOps智能运维:从数据治理到故障自愈的实践指南

AIOps(智能运维)通过融合人工智能与运维管理,构建了感知-决策-执行的闭环体系。其核心技术包括多维度数据采集、机器学习算法和自动化执行,显著提升了告警治理、故障定位和容量预测的效率。在数据层,全量性、实时性的数据采集是基础,而算法层的异常检测和根因分析则依赖统计方法、孤立森林和LSTM等模型。AIOps尤其适用于处理告警风暴和复杂系统故障,如在电商大促中通过K-Means聚类减少92%的告警量。随着云原生和边缘计算的普及,AIOps正逐步实现与Service Mesh、Serverless等技术的深度集

weixin_30175731的博客 288

uniapp中使用JWT

使用简单的例子讲解了从后端SpringBoot到前端Uniapp使用JWT的过程。

qq_58331936的博客 2288

G2O (General Graph Optimization)入门及简单使用

g2o全称是General Graph Optimization,也就是图优化,我们在做SLAM后端或者更加常见的任何优化问题(曲线拟合)都可以使用G2O进行处理。

晓晨的博客 1万+

uni-app实战仿微信app开发

适用人群具有Html+Css+JavaScript基础,有一定的Vue.js基础,挑战高薪职位课程概述本季度为uni-app + egg.js 实战仿微信app和小程序全栈开发,开启纯nvue原生渲染,大大提高性能。一次开发,同时搞定Android、iOS和小程序端等。课程大纲见以下图!

Apollo MPC横纵向耦合控制学习笔记

Apollo MPC横纵向控制原理学习笔记

weixin_39199083的博客 1万+

基于NXP i.MX RT1180的无传感器FOC电机驱动实战指南

磁场定向控制(FOC)是一种先进的电机控制技术,它通过精密的数学变换,将三相交流电机的控制解耦为独立的转矩和磁场分量,从而实现高效、平稳、低噪音的驱动。其核心原理在于利用Park/Clark变换,在旋转坐标系下对电流进行线性控制。这项技术的价值在于显著提升了永磁同步电机(PMSM)的效率与动态性能,广泛应用于机器人、无人机和工业自动化等高精度场景。本文聚焦于利用NXP i.MX RT1180跨界处理器及其MCUXpresso SDK,快速实现一套完整的无传感器FOC解决方案。通过解析硬件平台选型、软件架构,

weixin_33925615的博客 305

微信小程序一键登录功能,使用uni-app和springboot(JWT鉴权)

使用uni-app开发微信小程序,实现微信一键登录功能,后端使用springboot进行登录的处理,使用JWT进行身份验证。

maohe的博客 1万+

grafana对接zabbix数据展示

【配置】点击【模板】点击【创建模板】添加三个监控项:【名称】搜索【】创建的模板;点击上方【监控项】,点击创建【监控项】点击上方【触发器】点击【创建触发器】主机关联监控模板:左侧【配置】点击 【主机】点击【Zabbix server】查看:左侧点击【监测】点击【主机】点击【Zabbix server】点击最新数据,找到添加的三个模板主机关联监控模板:左侧【配置】点击 【主机】点击【Zabbix server】把监控模板用起来① 明确获取指标数据的方法。

2401_83883919的博客 6594

Thinkphp-Laravel+uniapp微信小程序的文明城市创建平台设计与实现

本系统后端采用 PHP 语言搭配Thinkphp或者 Laravel 框架,PHP 语法简洁且功能强大,Laravel 或者Thinkphp框架能优化代码结构、提升开发效率,高效实现系统核心逻辑与数据库交互。前端运用 Vue 框架,其组件化开发与响应式设计,可打造流畅交互界面。MySQL 数据库稳定可靠,能安全存储海量文档数据,整体而言,这些成熟技术相互配合,能顺利完成系统开发。开发软件: hbuiderx,vscode、Adobe Dreamweaver等。

专注分享bishe530的博客 824

【STM32/GD32】Keil uVision生成bin文件:从编译选项到Bootloader升级实战

本文详细讲解了如何在Keil uVision中配置STM32/GD32工程,使其在编译后自动生成Bootloader升级所需的bin文件。通过解析fromelf工具的使用、构建后命令的配置以及内存布局规划,深入阐述了bin文件在固件升级中的核心作用,并提供了串口Bootloader的实战框架与常见问题解决方案。

weixin_29190169的博客 393

无人机基本组成部件

无人机基本组成部件

qq_37410522的博客 1万+

Thinkphp-Laravel+uniapp微信小程序的健康食品零食商城积分兑换的设计与实现_

健康食品零食商城积分兑换系统基于ThinkPHP-Laravel框架与Uniapp微信小程序开发,实现用户积分管理与商品兑换功能。系统采用前后端分离架构,后端使用ThinkPHP-Laravel提供RESTful API接口,前端通过Uniapp实现跨平台兼容性,适配微信小程序环境。系统核心功能包括用户积分获取、商品展示与兑换、订单管理及数据分析。用户通过每日签到、消费购物等行为累积积分,积分可用于兑换商城内的健康零食商品。商品模块支持分类展示、详情查看及积分兑换逻辑校验,确保用户积分充足时方可完成兑换。

懒人的博客 677

基于STM32单片机智能循迹小车毕业设计

本文介绍了一种利用STM32F103C8T6单片机为控制核心,结合多种传感器以及PID算法实现循迹避障功能的智能小车。随着我国高科技水平的不断提高和工业自动化进程的不断推进,智能小车被广泛应用于各种玩具和其他产品的设计中,极大地丰富了人们的生活。本次设计利用反射式红外光电传感器探测路面黑线实现小车循迹,利用超声波测距传感器探测路径上的障碍,控制小车自动避障,整个系统具有自动循迹、自动避障、速度检测和无线遥控功能。其中,控制部分采用STM32F103C8T6单片机,STM32F103C8T6单片机是一

qq_48771816的博客 3974

微信小程序的uniapp选修课管理系统的设计与实现Thinkphp-Laravel框架项目源码开发实战

该系统基于UniApp跨平台框架与ThinkPHP-Laravel混合后端架构开发,实现高校选修课全流程数字化管理。前端采用微信小程序作为主要入口,兼容H5端,利用UniApp的跨端特性实现代码复用;后端结合ThinkPHP的高效数据操作与Laravel的优雅设计模式,通过RESTful API提供数据交互。核心功能模块学生端:课程查询与筛选、在线选课/退课、课表同步、成绩查询及评价反馈。教师端:课程发布与管理、学生名单导出、成绩录入与统计分析。管理端。

bishe288的博客 783

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

Thinkphp和Laravel框架都支持基于uniapp的高校教室预约管理平台可视化-小程序

2、同时增加文字触发提醒,设置提醒语,有相同字段的数据,会触发弹框提醒,例如设置状态提醒:特急/加急/一般 增加自定义提醒语(如:库存不足,请补货)秒速登进去,特别省事。对于本系统,我们提供全方位的支持,包括修改时间和标题,以及完整的安装、部署、运行和调试服务,确保系统能在你的电脑上顺利运行。AI续写、AI优化、AI校对、AI翻译:新增AI接口,编辑器接入AI,可以实现AI续写、AI优化、AI校对、AI翻译,可以帮你实现自动化,ai帮你完成文档。此信息只能使用查看,可以登录进去操作,就是类似于真机调试,

QQ511008285的博客 396

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

Thinkphp-Laravel+uniapp微信小程序+的瑜伽馆课程预约选课管理系统

该系统基于ThinkPHP-Laravel框架与Uniapp微信小程序开发,旨在为瑜伽馆提供高效的课程预约与选课管理解决方案。后端采用ThinkPHP-Laravel混合架构,结合两者的优势实现高并发处理与模块化开发,确保系统稳定性和扩展性。前端通过Uniapp跨平台技术开发微信小程序,支持用户随时随地预约课程、查看课表、管理个人订单等功能,提升用户体验。系统核心功能包括会员管理、课程发布与排期、在线预约与支付、选课统计与分析等。

懒人的博客 662

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

ThinkPHP与Laravel混合架构开发微信小程序健康饮食系统

现代Web开发中,PHP框架的选择直接影响系统架构的扩展性和维护性。ThinkPHP以其简洁高效著称,特别适合快速构建后台管理系统;而Laravel凭借优雅的语法和丰富的扩展包,成为复杂业务逻辑的首选。通过JWT认证和RESTful API设计,两种框架可以在微信小程序等移动端项目中协同工作,实现权限控制与业务逻辑的分离。在健康饮食推荐场景中,这种混合架构既能利用ThinkPHP的RBAC模块快速搭建管理后台,又能基于Laravel的队列系统和算法包实现个性化推荐。典型应用还包括需要兼顾开发效率与性能要求的

weixin_30267785的博客 419

微信小程序的uniapp校园活动报名管理系统设计与实现Thinkphp-Laravel框架项目源码开发实战

本系统后端采用 PHP 语言搭配Thinkphp或者 Laravel 框架,PHP 语法简洁且功能强大,Laravel 或者Thinkphp框架能优化代码结构、提升开发效率,高效实现系统核心逻辑与数据库交互。前端运用 Vue 框架,其组件化开发与响应式设计,可打造流畅交互界面。MySQL 数据库稳定可靠,能安全存储海量文档数据,整体而言,这些成熟技术相互配合,能顺利完成系统开发。开发软件: hbuiderx,vscode、Adobe Dreamweaver等。

bishe288的博客 919

Thinkphp-Laravel+uniapp微信小程序高校学生兼职系统的设计与实现

随着移动互联网的快速发展,高校学生兼职需求日益增长,传统兼职信息发布方式存在信息不对称、管理效率低等问题。基于ThinkPHP-Laravel框架与UniApp技术,设计并实现了一款高校学生兼职系统,旨在为学生提供便捷的兼职信息获取渠道,同时为企业提供高效的人才招募平台。系统采用前后端分离架构,后端基于ThinkPHP-Laravel框架开发,提供稳定的RESTful API接口,实现用户管理、兼职信息发布、申请审核等功能。

专注分享bishe530的博客 613

uniapp学生英语选课在线学习打卡系统 小程序php python

Uniapp学生英语选课在线学习打卡系统是一款基于Uniapp框架开发的跨平台小程序,支持学生选课、在线学习、打卡签到等功能。后端可采用PHP或Python实现,提供课程管理、用户认证、数据统计等接口。

QQ_511008285的博客 1132

uniapp

无感刷新。

huowen123000的博客 445

微信小程序的uniapp餐厅预约系统设计与实现Thinkphp-Laravel框架项目源码开发实战

该系统基于微信小程序平台,采用Uniapp跨端框架开发前端界面,后端选用ThinkPHP-Laravel混合框架实现高并发数据处理与业务逻辑。设计目标为提升餐厅运营效率,优化用户预约体验,涵盖桌位管理、在线预约、订单支付、数据统计等核心功能模块。技术架构前端使用Uniapp实现多端兼容(微信小程序、H5),通过Vue.js数据绑定与组件化开发提升交互体验;后端采用ThinkPHP-Laravel双框架分层设计,ThinkPHP处理基础CRUD操作,Laravel负责复杂业务逻辑与API接口。

bishe288的博客 875

Thinkphp和Laravel框架都支持基于uniapp的固定资产借用租赁管理平台- 小程序

简单说,一个管安全规则,一个管身份凭证,组合起来为Web应用打造可靠防护。2、同时增加文字触发提醒,设置提醒语,有相同字段的数据,会触发弹框提醒,例如设置状态提醒:特急/加急/一般 增加自定义提醒语(如:库存不足,请补货)对于本系统,我们提供全方位的支持,包括修改时间和标题,以及完整的安装、部署、运行和调试服务,确保系统能在你的电脑上顺利运行。AI续写、AI优化、AI校对、AI翻译:新增AI接口,编辑器接入AI,可以实现AI续写、AI优化、AI校对、AI翻译,可以帮你实现自动化,ai帮你完成文档。

QQ511008285的博客 389

微信小程序 PHP_uniapp的大学生校园生活服务系统的 二手 自习室 会议 失物招领40ifxo7d

本系统后端采用 PHP 语言搭配Thinkphp或者 Laravel 框架,PHP 语法简洁且功能强大,Laravel 或者Thinkphp框架能优化代码结构、提升开发效率,高效实现系统核心逻辑与数据库交互。前端运用 Vue 框架,其组件化开发与响应式设计,可打造流畅交互界面。MySQL 数据库稳定可靠,能安全存储海量文档数据,整体而言,这些成熟技术相互配合,能顺利完成系统开发。开发软件: hbuiderx,vscode、Adobe Dreamweaver等。

QQ58850198的博客 951

php+uniapp的个人理财家庭财务收支系统422vl 小程序

本次毕业设计主要围绕老师要求的设计与实现展开,通过综合运用现代信息技术,旨在解决传统管理系统中存在的流程冗杂、信息孤岛化、评审透明度不足等问题。在系统的设计与实现过程中,我们采用了SpringBoot框架和MySQL数据库等先进技术,实现了系统的前后端分离、模块化设计以及高效的数据处理与存储功能。通过本次毕业设计,我成功构建了一个高效、安全、易用的毕业设计定系统。该系统不仅提高了传统的效率和透明度。同时,系统的无纸化操作也符合当前环保和可持续发展的理念。

懒人的博客 714

基于ThinkPHP与Laravel的高校招聘系统开发实践

现代Web开发框架如ThinkPHP和Laravel为构建高性能招聘系统提供了强大支持。ThinkPHP以其快速开发特性适合处理本土化业务需求,而Laravel则凭借优雅的代码结构和丰富生态支撑复杂系统架构。在高校招聘场景中,通过混合使用这两个PHP框架,开发者能实现包括智能岗位匹配、高并发面试预约等核心功能。关键技术涉及RESTful API设计、Redis缓存优化及MySQL读写分离,有效解决了传统招聘会信息不对称、效率低下等痛点。这种架构特别适合需要同时支持App和小程序的多终端访问场景,为校企对接提

weixin_33985679的博客 338
上一篇: 创建一个日期+字符的用户名
下一篇: 记录一个 uniapp-checkbox 如何动态改变勾选状态
yt_php
博客等级 码龄9年 73粉丝 133原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值