下面以一个登陆的例子给大家介绍一下
创建项目
打开HBuilderX -> 新建 uniapp 项目;
创建页面
|_ index.vue 入口页面 |_ write.vue 文章撰写页面 |_ my.vue 账户中心页面后端使用php+mysql
完善底部导航栏下载图标, 图标地址 :
https://pan.baidu.com/s/1iaWd6l_-cIJ3RNUsqNqFNQ将图标部署至 /static 目录;
修改 page.json
"tabBar" : {
"color" : "#707070", "selectedColor" : "#DE533A", "list" : [ { "pagePath" : "pages/index/index", "text" : "文章", "iconPath" : "static/nav1.png", "selectedIconPath" : "static/nav1-a.png" }, { "pagePath" : "pages/write/write", "text" : "写作", "iconPath" : "static/nav2.png", "selectedIconPath" : "static/nav2-a.png" }, { "pagePath" : "pages/my/my", "text" : "我的", "iconPath" : "static/nav3.png", "selectedIconPath" : "static/nav3-a.png" } ] }
4.修改项目名称
"globalStyle" : {
"navigationBarTextStyle" : "black", "navigationBarTitleText" : "悦读", "navigationBarBackgroundColor" : "#F8F8F8", "backgroundColor" : "#F8F8F8"}
5.加载 colorUI 框架
https://github.com/weilanwl/ColorUI
1、在 main.js 中封装全局登录函数
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 == '' || SRAND == '' || SFACE == ''){ uni.redirectTo({url:'../login/login?backpage='+backpage+'&backtype='+backtype}); return false; } return [SUID, SRAND, SNAME, SFACE];}
参数说明
backpage, backtype 2个参数分别代表: backpage : 登录后返回的页面 backtype : 打开页面的类型[1 : redirectTo 2 : switchTab] 返回值说明 已经登录返回数组 [用户 id, 用户随机码, 用户昵称, 用户表情]
2、创建 login 页面
login 页面作为登录过度页面,多端登录都通过此页面完成!
3、在页面中应用登录检查函数,如 write.vue
<script>
export default { data() { return { }; }, onLoad : function() { var loginRes = this.checkLogin('../my/my', '2'); if(!loginRes){return false;} }}</script>
return 或终止函数运行哦!
<script>
export default { data() { return { }; }, onLoad:function(){ //app 端
微信登录 // 手册位置 https://uniapp.dcloud.io/api/plugins/login?id=getuserinfo // #ifdef APP-PLUS uni.login({ success: (res) => { // res 对象格式 //{"code":"***", //"authResult":{ //"openid":"***", //"scope":"snsapi_userinfo", //"refresh_token":"**", //"code":"****", //"unionid":"***", //"access_token":"***", //"expires_in":7200 //}, //"errMsg":"login:ok"} uni.getUserInfo({ success: (info) => { // info 对象格式 // {"errMsg":"getUserInfo:ok", // "rawData":"... // "userInfo":{ //"openId":"***", //"nickName":"***", //"gender":1, // "city":"Xi'an", // "province":"Shaanxi", // "country":"China", // "avatarUrl":"头像", // "unionId":"oU5Yyt_agt547zWyA0v0eLfFPqxo" //},"signature":""} // 与服务器交互将数据提交到服务端数据库 }, fail: () => { uni.showToast({title:"
微信登录授权失败"}); } }) }, fail: () => { uni.showToast({title:"
微信登录授权失败"}); } }) // #endif }}</script>
多平台统一登录之 unionID
通过获取用户基本信息接口,开发者可通过OpenID来获取用户基本信息,而如果开发者拥有多个应用,可使用以下办法通过UnionID机制来在多个应用进行用户帐号互通。
只要是同一个
微信开放平台帐号下的公众号,用户的UnionID是唯一的。
换句话说,同一用户,对同一个微信开放平台帐号下的不同应用,UnionID是相同的。
此前的OpenID机制,每个
微信号对应每个应用有唯一的OpenID,所以不同应用之间是不能共享用户的,现在有了UnionID就可以了。
APP端获取 unionID
使用 uni.login 即可;
小程序端获取 unionID
步骤 :
1、配置小程序 appid (此appid 在微信开放平台已经绑定);
2、使用 uni.login 登录时会获取 code,用 code 换取 seesion_key; 3、在获取用户信息函数中获取到加密信息; 4、利用 seesion_key 及加密信息在服务端解密获取 unionID
php 后端注意事项
需要开启 php_openssl 扩展
前端实现过程代码
export default {
data() { return { }; }, methods:{ // #ifdef MP-WEIXIN getUserInfo : (info) => { //加密数据 var encryptedData = info.mp.detail.encryptedData; var iv = info.mp.detail.iv; info = info.mp.detail.userInfo; //info //userInfo {"nickName":"深海","gender":1,...avatarUrl":"https://7tdPvkPaJlkaLFFbLAffGVApluZdanLkDVplNlAhq1EJA/132"} //与服务器交互进行解密 uni.request({ url: _self.apiServer+'member&m=wxaes', method: 'POST', header: {'content-type' : "application/x-www-form-urlencoded"}, data: { session_key : session_key, encryptedData : encryptedData, iv : iv }, success: res => { console.log(res); //此处可以成功获取 unionId 利用 unionId 完成登录即可 }, fail: () => {}, complete: () => {} }); } }, onLoad:function(options){ _self = this; pageOptions = options; // #ifdef MP-WEIXIN // 调用
微信login 获取 code uni.login({ success: (res) => { uni.request({ url:_self.apiServer+'member&m=codeToSession&code='+res.code, success: (sessions) => { session_key = sessions.data.session_key; } } } }); } }); // #endif}
php 后端代码
<?php
namespace hsC;class member{ //...... public function wxaes(){ if(empty($_POST['session_key']) || empty($_POST['encryptedData']) || empty($_POST['iv'])){exit(jsonCode('error', 'data error'));} include HS_TOOLS.'WXBizDataCrypt.php'; $pc = new WXBizDataCrypt(HS_APPID, $_POST['session_key']); $data = ''; $errCode = $pc->decryptData($_POST['encryptedData'], $_POST['iv'], $data); if ($errCode == 0) { exit($data); } else { exit(jsonCode('error', $errCode)); } }}
安全概述
前面章节讲解的接口是裸露的、不安全的!使用post、get模拟可以轻松对api进行请求,最简单的攻击就可以瞬间完成近万会员的注册! 所以在进行api接口通讯的同时我们应该进行数据的验证工作!
加密原理及流程
1、从服务器端获取一个唯一性的token,我们称之为 accessToken;
2、前端对accessToken进行随机性拆分及md5加密,产生签名(保存在本地存储中); 3、前端在与后端进行交互时传递签名; 4、后端接收数据是验证签名;
签名准备
1、在 commons 文件夹内创建
1.1 md5.js //js md5 加密 [ 在课程内获取此 js文件 ]
1.2 sign.js // 签名函数
sign.js
var md5 = require('./md5.js');
module.exports = { sign : function(apiServer){ // 环境判断非uni环境不支持 if(!uni){return '...';} // 连接服务器获取一个临时的accessToken uni.request({ url: apiServer+'getAccessToken', method: 'GET', success: res => { if(res.data.status != 'ok'){return ;} var data = res.data.data; // 对 accessToken 进行md5加密 var accessToken = md5.hex_md5(data.token + data.time); // 签名 = md5(accessToekn + time) + '-' + 'accessToekn'; var sign = accessToken + '-' + data.token; //console.log(sign); // 记录在本地 uni.setStorage({ key:"sign", data:sign }); } }); }}
数据库
DROP TABLE IF EXISTS `yuedu_access_tokens`;
CREATE TABLE `yuedu_access_tokens` ( `token` varchar(30) NOT NULL, `time` int(11) DEFAULT NULL, PRIMARY KEY (`token`)) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4;
php 端代码
<?php
//getAccessToken.phpnamespace hsC;class getAccessToken{ public function index(){ $db = hsTooldb::getInstance('access_tokens'); $token = array( 'token' => uniqid(), 'time' => time() ); $db->add($token); exit(jsonCode('ok', $token)); }}
使用说明
在数据提交页面提交之前进行预签名,提交数据时携带此签名!
更合理的签名保存
因为大家后端基础不一样,本课程使用数据库保存了accessToken,更好的方式是 redis 或 memcache,可以设置变量有效期并能自动失效!