本次学习为hcoder.net提供的原始教程,本文为学习笔记(对部分做了完善和扩展),仅供各位参考!
如若学习,请参见原版教程,支持正版,谢谢!
本项目为初学者项目,功能简单,就不做项目演示站了,贴上项目图片:
项目建立,本次为学习uniapp官方教程的学习笔记:
一、建立项目、配置公共登陆函数新建--项目--uniapp项目--默认模版,进入main.js,编写公共登陆函数:Vue.config.productionTip = false
...
Vue.prototype.checkLogin = function(backpage,backtype){ //定义一个登陆检查函数
var SUID = uni.getStorageSync("SUID"); //从缓存里取值
var SRAND = uni.getStorageSync("SRAND");
var SNAME = uni.getStorageSync("SNAME");
var SFACE = uni.getStorageSync("SFACE");
if(SUID == '' || SNAME == '' || SRAND == ''){ //如果没有值,跳转登陆页
uni.redirectTo({url:'../login/login?backpage='+backpage+'&backtype='+backtype});
console.log("qqw");
return false;
}
return [SUID, SRAND, SNAME, SFACE]; //有值的话,返回值
}
...
App.mpType = 'app'新建页面,调用公共登陆函数,检查登陆:
内容页面
var loginres;
export default {
data() {
return {
}
},
onLoad() {//加载页面先判断是否登陆
//console.log(options)
var Loginres = this.checkLogin('../index/index', 2) //调用公共的登陆检查函数
console.log(Loginres);
if(!Loginres){return false;} //如果返回值不存在,返回false
},
methods: {
}
}
二、服务端代码及配置服务端源码
你可以在文末或页面右侧的资源包里下载本次项目的服务端源码,上传至服务端,并在index.php配置数据库信息
数据库
你可以使用Navicat等数据库工具,建立新的数据表,并执行以下语句,创建表字段:CREATE TABLE `yuedu_members` (
`u_id` int(11) NOT NULL AUTO_INCREMENT COMMENT '用户id',
`u_openid` varchar(100) NOT NULL COMMENT 'openid',
`u_name` varchar(50) NOT NULL COMMENT '用户昵称',
`u_face` varchar(200) NOT NULL COMMENT '用户头像',
`u_random` varchar(30) NOT NULL COMMENT '用户随机码',
`u_integral` int(10) DEFAULT '0' COMMENT '积分',
`u_remainder` int(10) DEFAULT '0' COMMENT '余额',
`u_regtime` int(11) NOT NULL COMMENT '用户注册时间',
PRIMARY KEY (`u_id`),
UNIQUE KEY `u_openid` (`u_openid`),
UNIQUE KEY `u_id` (`u_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4;或者可以手敲php端
php原理:
这里说一下php的运行原理 ,看图
php的设计模式
MVC(models、controllers、views)和index.php
C控制器层:对不同的业务
M模型:分为数据模型和业务逻辑模型
V视图:本项目因为是前后端分离,不包含V视图层
用户首先进入index.php,进入控制器,由控制器进入视图层和模型层
控制器调用其他静态类:
以下为后端php方面代码的手记
在index.php中新建访问规则:index.php入口文件的编写(详细查看注释)<?php
/*
*oldlee
*/
//设置编码
header('content-type:text/html; charset=utf-8');
// 接口认证,每次的接口访问都带上token,token可以自定义
if(empty($_GET['token'])){exit(jsonCode('error', 'token error'));} //如果没有token,结束并token error
if($_GET['token'] != 'api2020'){exit(jsonCode('error', 'token error'));}//如果token不对,结束并token error
//定义常量
// 文件夹的定义
define("HS_DS" , DIRECTORY_SEPARATOR);
define("HS_ROOT" , dirname(__FILE__).HS_DS);
define("HS_CONTROLLERS" , HS_ROOT.'controllers'.HS_DS);
define("HS_MODELS" , HS_ROOT.'models'.HS_DS);
define("HS_TOOLS" , HS_ROOT.'tools'.HS_DS);
/* 过滤及定义 POST 减少跨站攻击的可能性*/
if(!empty($_POST)){
define("IS_POST", false);
}else{
define("IS_POST", true);
$_POST = str_replace(array('', '"', "'"),array('<','>', '"', ''), $_POST); //过滤尖括号,引号等
}
// 数据库配置
define('HS_DB_HOST' , '127.0.0.1'); // mysql 服务器地址
define('HS_DB_NAME' , '***'); // 数据库名称
define('HS_DB_USER' , 'root'); // 数据库账号
define('HS_DB_PWD' , '***'); // 数据库密码
define('HS_DB_PRE' , '***'); // 数据表统一前缀
define('HS_DB_CHARSET' , 'utf8'); // mysql 字符集类型
// 微信小程序相关设置
define('HS_APPID' , '*****');
define('HS_SECRET' , '*****');
// 自动加载各种控制器、方法和类
function hsAutoLoad($className){
$className = explode('\', $className);
if(empty($className[0])){array_shift($className);}
if(count($className) != 2){return false;}
switch($className[0]){
case 'hsModel':
$classFileName = HS_MODELS.$className[1].'.php';
break;
case 'hsTool':
$classFileName = HS_TOOLS.$className[1].'.php';
break;
}
if(empty($classFileName)){return false;}
if(is_file($classFileName)){require $classFileName;}
}
spl_autoload_register("hsAutoLoad");
// 路由解析
$_GET['c'] = empty($_GET['c']) ? 'index' : $_GET['c'];
$_GET['m'] = empty($_GET['m']) ? 'index' : $_GET['m'];
$pattern = '/^[a-zA-Z]+[0-9]*[a-zA-Z]*$/';
if(!preg_match($pattern, $_GET['c'])){$_GET['c'] = 'index';}
if(!preg_match($pattern, $_GET['m'])){$_GET['m'] = 'index';}
$controllerFileName = HS_CONTROLLERS.$_GET['c'].'.php';
if(is_file($controllerFileName)){
require $controllerFileName;
$className = '\\hsC\'.$_GET['c'];
$controller = new $className;
if(method_exists($controller, $_GET['m'])){
call_user_func(array($controller, $_GET['m']));
}
}
// json 输出
function jsonCode($status, $data){
return json_encode(array('status' => $status, 'data' => $data));
}
// 签名验证
function checkSign(){
if(empty($_POST['sign'])){exit(jsonCode('error', 'sign error'));}
$sign = explode('-', $_POST['sign']);
if(count($sign) != 2){exit(jsonCode('error', 'sign error'));}
$db = \hsTool\db::getInstance('access_tokens');
$token = $db->where('token = ?', array($sign[1]))->fetch();
if(empty($token)){exit(jsonCode('error', 'sign error'));}
$signMd5 = md5($token['token'].$token['time']);
if($signMd5 != $sign[0]){exit(jsonCode('error', 'sign error'));}
// 验证成功则删除
$db->where('token = ?', array($sign[1]))->delete();
}
// 验证用户合法性
function checkUser(){
if(empty($_POST['uid'])){exit(jsonCode('error', 'uid error'));}
if(empty($_POST['random'])){exit(jsonCode('error', 'random error'));}
$db = \hsTool\db::getInstance('members');
$user = $db->where('u_id = ?', array($_POST['uid']))->fetch();
if(empty($user)){exit(jsonCode('error', 'user error'));}
if($user['u_random'] != $_POST['random']){exit(jsonCode('error', 'user error'));}
return $user;
}
在控制器或者模型方法里,即可返回对应的内容至前端,如echo和return等:前端接收和提交数据(定义在main.js中)://定义公共的api接口
var apitoken = 'api2020';
Vue.prototype.apiService = 'http://yuedu.oldlee.cn/index.php?token='+apitoken+'&c=';
三、用户登录
这里使用条件编译对各端的登陆做控制和区分,先使用uni.login获取用户基础信息,再调用uni.getUserInfo获取用户详细信息:
APP端登陆用户详细信息的获取(包含了unionid)// #ifdef APP-PLUS //条件编译
uni.login({ //获取基础信息
success: (res) => {
console.log(res);
uni.getUserInfo({ //获取详细信息
success: (info) => {
console.log(info);
},
fail: () => {
uni.showToast({title:"微信登录授权失败"});
}
})
},
fail: () => {
uni.showToast({title:"微信登录授权失败"});
}
})
// #endif
打印:
APP端用户登陆,并提交用户信息到服务端:
APP端用户登录的后端代码:
APP端用户登录的前端代码:// #ifdef APP-PLUS
uni.login({
success: (res) => {
console.log(res);
//-------------------------
uni.getUserInfo({
success: (info) => {
//***********************
uni.request({
url: _self.apiService+'member&m=login',
method: 'POST',
header: {'content-type' : "application/x-www-form-urlencoded"},
data: {
openid : info.userInfo.openId,
name : info.userInfo.nickName,
face : info.userInfo.avatarUrl,
},
success: res => {
console.log(res);
},
fail: () => {},
complete: () => {}
});
//***********************
},
fail: () => {
uni.showToast({title:"微信登录授权失败"});
}
})
//-------------------------
},
fail: () => {
uni.showToast({title:"微信登录授权失败"});
}
})
// #endif
服务端返回结果打印:
APP端用户登陆信息返回成功后,对用户信息缓存并跳转:
在获取服务端返回值后,哪找返回值中data中的status的值来判断是否登陆成功,为“ok”,即登陆成功:
然后,将服务端返回的用户信息进行缓存,并根据全局变量的跳转地址和方式进行跳转:success: res => {
//console.log(res); 登陆成功
//{"data":{"status":"ok","data":{"u_openid":"...","u_name":"..","u_face":"..."}
if(res.data.status == 'ok'){ //如果登陆成功
uni.showToast({title:"登录成功"});
//进行缓存
//加个空格,使其转变为字符串
uni.setStorageSync('SUID' , res.data.data.u_id + '');
uni.setStorageSync('SRAND', res.data.data.u_random + '');
uni.setStorageSync('SNAME', res.data.data.u_name + '');
uni.setStorageSync('SFACE', res.data.data.u_face + '');
//根据访问登陆页面之前的页面带过来的页面地址和跳转方式,进行跳转
if(options.backtype == 1){
uni.redirectTo({url:options.backpage});
}else{
uni.switchTab({url:options.backpage});
}
}else{ //否则直接弹出错误信息
uni.showToast({title:res.data.data.});
}
}
APP端登陆完成;微信小程序端用户登陆(后端代码同上方APP登陆的后端代码)
通过uni.login获取用户基本信息:
打开manifest.json,找到微信小程序配置,填写app