后台操作
/**
* 授权登录
* @return \think\response\Json
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function create()
{
$code = input('code');//前台传过来的
$AppID = 'wx101e36c98383213e';//微信公众平台获取
$AppSecret = 'e7005b757195845b865723d871142fce';
$url = 'https://api.weixin.qq.com/sns/jscode2session?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code';
$url = sprintf($url,$AppID,$AppSecret,$code);//sprinty()把百分号(%)符号替换成一个作为参数进行传递的变量:
$data=curlGet($url);
$user=Logins::where('openid',$data['openid'])->find();
if (empty($user)){
$user=Logins::create([
'openid'=>$data['openid'],
'session_key'=>$data['session_key']
]);
}else{
$user->session_key=$data['session_key'];
$user->save();
}
$token=(new Token())->generateToken($user->id);
return json(['token'=>$token,'msg'=>'登陆成功','code'=>0]);
}
获取手机号
/**
* 获取手机号
* @param Request $request
* @return Response
*/
public function phone(Request $request)
{
$data=$request->post();
// dd($data);
try{
$user=Logins::find($request->id);
$aeskey=base64_decode($user->session_key);
$aesIv=base64_decode($data['iv']);
$aesCipher=base64_decode($data['encryptedData']);
$result=openssl_decrypt($aesCipher,"AES-128-CBC",$aeskey,1,$aesIv);
$phoneNumber=json_decode($result,true)['purePhoneNumber'];
$user->phone=$phoneNumber;
$user->save();
return Response::create(['code'=>0,'msg'=>'手机号获取成功'],'json');
}catch (\Exception $e){
return Response::create(['code'=>10002,'data'=>'','msg'=>'手机号获取失败'],'json');
}
}
手机号发送验证码
/**
* 发送手机验证码
* @param Request $request
* @return \think\response\Json
*/
public function send(Request $request){
$phone = input();
if (empty($phone['phone']))
{
return Redirect::create(['error_code'=>500,'msg'=>'手机号不能为空!'],'json');
}
$statusStr = array(
"0" => "短信发送成功",
"-1" => "参数不全",
"-2" => "服务器空间不支持,请确认支持curl或者fsocket,联系您的空间商解决或者更换空间!",
"30" => "密码错误",
"40" => "账号不存在",
"41" => "余额不足",
"42" => "帐户已过期",
"43" => "IP地址限制",
"50" => "内容含有敏感词"
);
$smsapi = "http://api.smsbao.com/";
$user = "zhaochongbin"; //短信平台帐号
$pass = md5("@bin411325"); //短信平台密码
$content=rand(1000,9999);//要发送的短信内容
$phone = $request['phone'];//要发送短信的手机号码
$sendurl = $smsapi."sms?u=".$user."&p=".$pass."&m=".$phone."&c=".urlencode( "$content");
return json([
'code'=>200,
'data'=>$content,
'msg'=>'验证码'
]);
}
前端页面
<view class="container">
<view class="page-body">
<form catchsubmit="formSubmit" catchreset="formReset">
<view class="page-section">
<view class="page-section-title">手机号登录</view>
<view class="weui-cells weui-cells_after-title">
<view class="weui-cell weui-cell_input">
<view class="weui-cell__bd" style="margin: 30rpx 0" >
<input class="weui-input" name="phone" placeholder="请输入手机号" />
</view>
</view>
</view>
</view>
<view class="btn-area">
<button style="margin: 30rpx 0" type="primary" formType="submit">发送验证码</button>
</view>
</form>
<form catchsubmit="formSubmits" >
<view class="page-section">
<view class="page-section-title"></view>
<view class="weui-cells weui-cells_after-title">
<view class="weui-cell weui-cell_input">
<view class="weui-cell__bd" style="margin: 30rpx 0" >
<input class="weui-input" name="input" id="{{yz}}" placeholder="验证码" />
</view>
</view>
</view>
</view>
<view class="btn-area">
<button style="margin: 30rpx 0" type="primary" id="{{yz}}" formType="submit">登录</button>
</view>
</form>
</view>
</view>
前端js
Page({
/**
* 页面的初始数据
*/
data: {
yz:''
},
formSubmit(e){
var that=this;
//页面防抖
TimeID:-1
clearTimeout(this.TimeID);
this.TimeID = setTimeout(() => {
//4.准备发送请求获取数据
wx.request({
url: 'http://www.zb.com/api/login/send',
data:{
phone:e.detail.value.phone
},
success(res){
// console.log(res)
that.setData({
yz:res.data.data
})
if(res.data.error_code == 500){
wx.showToast({
title: res.data.msg,
icon:'error',
duration:2000
})
}
if(res.statusCode== 429)
{
wx.showToast({
title: '请求太过频繁',
icon:'error',
duration:2000
})
}
}
})
}, 1500)
},
formSubmits(e){
var yz=e.detail.target.id;
var yzs=e.detail.value.input;
if(yz==yzs){
wx.showToast({
title: '登录成功',
})
wx.navigateTo({
url: '/pages/index2/index2',
})
}else{
wx.showToast({
title: '验证码错误',
icon:'error'
})
}
},
})
前端css
.content {
width: 100%;
height: auto;
padding: 0 50rpx;
box-sizing: border-box;
}
.phone-box {
width: 100%;
height: 89rpx;
border-bottom: 1rpx solid #efefef;
display: flex;
flex-direction: row;
justify-content: flex-start;
align-items: center;
}
.phone {
color: #333;
margin-right: 60rpx;
font-size: 28rpx;
}
.number {
color: #333;
font-size: 28rpx;
width: 200rpx;
}
.getNum {
width:210rpx;
height:48rpx;
background:rgba(248, 112, 57, 1);
border-radius:8rpx;
font-size:28rpx;
font-family:PingFang-SC-Medium;
color:rgba(255, 255, 255, 1);
line-height:48rpx;
margin-right:36rpx;
text-align:center;
}
.submit {
width: 480rpx;
height: 80rpx;
background: rgba(248, 112, 57, 1);
border-radius: 8rpx;
margin-top: 80rpx;
color: #fff;
font-size: 32rpx;
}
阿里云上传
/**
* 阿里云上传
* @param Request $request
* @return \think\response\Json
*/
public function upload(Request $request)
{
$img = $request->file('file');
//获取图片原路径
$filePath = $img->getPathname();
$fileName=(new Oss())->uploadFile($filePath);
return json(['code'=>200,'msg'=>"上传成功",'url'=>$fileName]);
}
/**
* 大图片分片上传
* @param Request $request
* @return Response
*/
public function sliceUpload(Request $request)
{
$pathName=$request->file('file')->getPathname();
$fileName=(new Oss())->sliceUpload($pathName);
return Response::create(['code'=>200,'msg'=>'操作成功','url'=>$fileName],'json');
}
添加数据
/**
* 添加数据
* @return \think\response\Json
*/
public function store()
{
$data=input();
// dd($data);
try {
validate(User::class)->check([
'name' => $data['name'],
'tel' => $data['tel'],
'city'=>$data['city']
]);
$datas=\app\api\model\User::create($data);
return json(['code'=>200,'msg'=>'添加成功','data'=>$datas]);
}catch (ValidateException $e){
return json(['code'=>301,'msg'=>$e->getMessage()]);
}
}
封装oss
public function uploadFile($filePath)
{
// 阿里云主账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM账号进行API访问或日常运维,请登录 https://ram.console.aliyun.com 创建RAM账号。
$accessKeyId = config('oss.accessKeyId');
$accessKeySecret = config('oss.accessKeySecret');
// Endpoint以杭州为例,其它Region请按实际情况填写。
$endpoint = config('oss.endpoint');
// 存储空间名称
$bucket = config('oss.bucket');
// <yourObjectName>上传文件到OSS时需要指定包含文件后缀在内的完整路径,例如abc/efg/123.jpg
$fileName = date('Y-m-d', time()) . '/' . md5(time() . rand(1111, 9999999)) . '.png';
try {
$ossClient = new OssClient($accessKeyId, $accessKeySecret, $endpoint);
$result = $ossClient->putObject($bucket, $fileName, file_get_contents($filePath));
} catch (OssException $e) {
print $e->getMessage();
}
return $result['info']['url'];
}
public function sliceUpload($patnName)
{
// 阿里云主账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM账号进行API访问或日常运维,请登录RAM控制台创建RAM账号。
$accessKeyId = config('oss.accessKeyId');
$accessKeySecret = config('oss.accessKeySecret');
// Endpoint以杭州为例,其它Region请按实际情况填写。
$endpoint = config('oss.endpoint');
$bucket= config('oss.bucket');
$object = date('Y-m-d', time()) . '/' . md5(time() . rand(1111, 9999999)) . '.png';
$uploadFile = $patnName;
/**
* 步骤1:初始化一个分片上传事件,获取uploadId。
*/
try{
$ossClient = new OssClient($accessKeyId, $accessKeySecret, $endpoint);
//返回uploadId。uploadId是分片上传事件的唯一标识,您可以根据uploadId发起相关的操作,如取消分片上传、查询分片上传等。
$uploadId = $ossClient->initiateMultipartUpload($bucket, $object);
} catch(OssException $e) {
printf(__FUNCTION__ . ": initiateMultipartUpload FAILED\n");
printf($e->getMessage() . "\n");
return;
}
print(__FUNCTION__ . ": initiateMultipartUpload OK" . "\n");
/*
* 步骤2:上传分片。
*/
$partSize = 10 * 1024 * 1024;
$uploadFileSize = filesize($uploadFile);
$pieces = $ossClient->generateMultiuploadParts($uploadFileSize, $partSize);
$responseUploadPart = array();
$uploadPosition = 0;
$isCheckMd5 = true;
foreach ($pieces as $i => $piece) {
$fromPos = $uploadPosition + (integer)$piece[$ossClient::OSS_SEEK_TO];
$toPos = (integer)$piece[$ossClient::OSS_LENGTH] + $fromPos - 1;
$upOptions = array(
// 上传文件。
$ossClient::OSS_FILE_UPLOAD => $uploadFile,
// 设置分片号。
$ossClient::OSS_PART_NUM => ($i + 1),
// 指定分片上传起始位置。
$ossClient::OSS_SEEK_TO => $fromPos,
// 指定文件长度。
$ossClient::OSS_LENGTH => $toPos - $fromPos + 1,
// 是否开启MD5校验,true为开启。
$ossClient::OSS_CHECK_MD5 => $isCheckMd5,
);
// 开启MD5校验。
if ($isCheckMd5) {
$contentMd5 = OssUtil::getMd5SumForFile($uploadFile, $fromPos, $toPos);
$upOptions[$ossClient::OSS_CONTENT_MD5] = $contentMd5;
}
try {
// 上传分片。
$responseUploadPart[] = $ossClient->uploadPart($bucket, $object, $uploadId, $upOptions);
} catch(OssException $e) {
printf(__FUNCTION__ . ": initiateMultipartUpload, uploadPart - part#{$i} FAILED\n");
printf($e->getMessage() . "\n");
return;
}
printf(__FUNCTION__ . ": initiateMultipartUpload, uploadPart - part#{$i} OK\n");
}
// $uploadParts是由每个分片的ETag和分片号(PartNumber)组成的数组。
$uploadParts = array();
foreach ($responseUploadPart as $i => $eTag) {
$uploadParts[] = array(
'PartNumber' => ($i + 1),
'ETag' => $eTag,
);
}
/**
* 步骤3:完成上传。
*/
try {
// 执行completeMultipartUpload操作时,需要提供所有有效的$uploadParts。OSS收到提交的$uploadParts后,会逐一验证每个分片的有效性。当所有的数据分片验证通过后,OSS将把这些分片组合成一个完整的文件。
$ossClient->completeMultipartUpload($bucket, $object, $uploadId, $uploadParts);
} catch(OssException $e) {
printf(__FUNCTION__ . ": completeMultipartUpload FAILED\n");
printf($e->getMessage() . "\n");
return;
}
return "https://zhaochongbin.oss-cn-hangzhou.aliyuncs.com/".$object;
}
封装token
class Token
{
protected $salt;
public function __construct()
{
$this->salt=config('jwt.salt');
}
/**
*
* 生成token
* @param $uid
* @return string
*/
function generateToken($uid)
{
//获取当前时间戳
$currentTime = time();
$data = array(
"iss" => 'keZuo', //签发者 可以为空
"aud" => '', //面象的用户,可以为空
"iat" => $currentTime, //签发时间
"nbf" => $currentTime, //立马生效
"exp" => $currentTime + 7200, //token 过期时间 两小时
"data" => [ //记录的userid的信息,这里是自已添加上去的,如果有其它信息,可以再添加数组的键值对
'uid' => $uid,
]
);
//生成token
$token = JWT::encode($data, $this->salt, "HS256"); //根据参数生成了 token
return $token;
}
/**
* 验证token
* @param $token
* @return int[]
*/
public function chekToken($token)
{
$status = array("code" => 2);
try {
JWT::$leeway = 60;//当前时间减去60,把时间留点余地
$decoded = JWT::decode($token, $this->salt, array('HS256')); //HS256方式,这里要和签发的时候对应
$arr = (array)$decoded;
$res['code'] = 1;
$res['data'] = $arr['data'];
return $res;
} catch (\Firebase\JWT\SignatureInvalidException $e) { //签名不正确
$status['msg'] = "签名不正确";
return $status;
} catch (\Firebase\JWT\BeforeValidException $e) { // 签名在某个时间点之后才能用
$status['msg'] = "token失效";
return $status;
} catch (\Firebase\JWT\ExpiredException $e) { // token过期
$status['msg'] = "token失效";
return $status;
} catch (\Exception $e) { //其他错误
$status['msg'] = "未知错误";
return $status;
}
}
}
微信小程序
<button open-type="getPhoneNumber" bindgetphonenumber="getPhoneNumber">获取手机号</button>
微信小程序js
/**
* 获取手机号
* @param {*} e
*/
getPhoneNumber(e){
// console.log(e)
wx.request({
url: 'http://www.zb.com/api/login',
header:{
'token':wx.getStorageSync('token')
},
data:{
iv: e.detail.iv,
encryptedData: e.detail.encryptedData
},
method: 'POST',
success:res=>{
// console.log(res)
if(res.data.code==0){
wx.setStorageSync('phone', 1)
this.setData({phone:true
})
wx.showToast({
title: '手机号授权成功',
icon:'success',
})
wx.navigateTo({
url: '/pages/index2/index2',
})
}else{
wx.showToast({
title: '手机号授权失败',
icon:'error'
})
}
}
})
}
授权登录
// 登录
wx.login({
success: res => {
wx.request({
url: 'http://www.zb.com/api/wxlogin',
data:{
code:res.code
},
success:ret=>{
let token=ret.data.token
wx.setStorageSync('token', token)
}
})
}
})
},
页面:
<l-steps active-index="0" >
<l-step title="主体认证"></l-step>
<l-step title="开始赚钱" ></l-step>
</l-steps>
<form bindsubmit="formAdd">
<l-input label="证件名称" name="name" placeholder="请输入证件名称" />
<l-input label="证件号码" name="tel" placeholder="请输入证件号码" />
<view class="section">
<view class="section__title">有效期</view>
<picker mode="date" value="{{date}}" start="2015-09-01" end="2017-09-01" bindchange="bindDateChange">
<view class="picker">
当前选择: {{date}}
</view>
</picker>
</view>
<l-image-picker count="9" bind:linchange="onChangeTap" bind:linremove="removeImage"/>
<button type="default" form-type="submit">下一步</button>
</form>
页面js
import WxValidate from '../../utils/WxValidate';
Page({
/**
* 页面的初始数据
*/
data: {
urls:[],
//选择地址
date:"请选择有效期",
name:'',
tel:''
},
//图片上传
onChangeTap(evn){
//获取最新上传的所有图片临时路径
let tempFilePaths = evn.detail.current;
//定义一个空数组,进行存放上传图片url
var urlArr = [];
for (let index = 0; index<tempFilePaths.length; index++) {
wx.uploadFile({
url: 'http://www.zb.com/api/upload', //仅为示例,非真实的接口地址
filePath: tempFilePaths[index],
name: 'file',
success: res => {
const data = JSON.parse(res.data);
//do something
urlArr.push(data.url)
this.setData({
urls: urlArr
})
},
})
}
},
bindDateChange: function(e) {
this.setData({
date: e.detail.value
})
},
// //地址绑定事件
// map(){
// wx.chooseLocation({
// success:ret=>{
// // console.log(ret)
// this.setData({
// date:ret.name +ret.address
// })
// }
// })
// },
//添加数据
formAdd(e){
console.log(e);
const params=e.detail.value
if(!this.WxValidate.checkForm(params)){
const error = this.WxValidate.errorList[0]
wx.showToast({
title:error.msg,
icon:'error',
duration:2000
})
}
wx.request({
url: 'http://www.zb.com/api/login/store',
data:{
name:e.detail.value.name,
city:this.data.date,
tel:e.detail.value.tel
},
})
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
this.initValidate();
},
initValidate(){
const rules={
name:{
required:true,
},tel:{
required:true,
idcard:true
}
};
const messages={
name:{
'required':'证件名称不为空'
},tel:{
'required':'证件号码不为空',
'idcard':'身份证号错误'
}
}
this.WxValidate=new WxValidate(rules,messages)
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady: function () {
},
/**
* 生命周期函数--监听页面显示
*/
onShow: function () {
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide: function () {
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload: function () {
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh: function () {
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom: function () {
},
/**
* 用户点击右上角分享
*/
onShareAppMessage: function () {
}
})