后台,安装laravel7配置passport
用passport实现接口的登录和jwt生成(生成token)
安装passport插件
composer require laravel/passport
或
composer require laravel/passport "^9.0"
 执迁迁移文件,生成数据表,保存token数据
php artisan migrate

生成客户端授权码
php artisan passport:install
Encryption keys generated successfully.
Personal access client created successfully.
Client ID: 1
Client secret: 6AS6JW79GMdhTUAJhjMN6nVFy8HMvtIGXFNqJiGX
Password grant client created successfully.
Client ID: 2
Client secret: KpZOwXE321ytcNuIYuWoJoVeEOhvcL3odLLIVbFJ

修改接口账号模型
use Laravel\Passport\HasApiTokens;

修改config/auth.php文件中的api配置 
令牌的有效期
在app/Proivders/AuthServiceProvide.php文件中的boot方法添加有效期
use Laravel\Passport\Passport;
// token认证有效期2小时
Passport::tokensExpireIn(now()->addHour(2));
// 刷新token认证有效期30天
Passport::refreshTokensExpireIn(now()->addDays(30));

实现登录,并且注意,如果登录不成功,数据返回符合restful规范 ** return response()->json([‘errorCode’ => 0, ‘data’ => [‘token’ => $token, ‘expire’ => 7200,‘time’=>time()], ‘msg’ => ‘登录成功’],200);**
路由
<?php
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
Route::middleware('auth:api')->get('/user', function (Request $request) {
return $request->user();
});
Route::group(['prefix'=>'v1','namespace'=>'Api'],function (){
Route::post('wx_login','LoginController@wxLogin');
});
Route::group(['middleware'=>'auth:api','prefix'=>'v1','namespace'=>'Api'],function (){
Route::put('users','LoginController@saveUsers');
Route::get('activity_list','GoodsController@activityList');
Route::get('goods_detail','GoodsController@goodsDetail');
Route::post('snap_up','GoodsController@checkStock');
Route::post('goods_order','GoodsController@createOrder');
});
Route::get('stock','Api\GoodsController@syncStock');
微信登录获取openid
配置文件

<?php
return [
'AppID' => 'wxf9c53e0a497cc457',
'AppSecret' => '47646ed2a1f74e056ab42cd6777cd500',
'wxLoginUrl'=>'https://api.weixin.qq.com/sns/jscode2session?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code'
];
login控制器
<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use GuzzleHttp\Client;
use App\Models\Renting;
use Illuminate\Support\Facades\Cache;
class LoginController extends Controller
{
public function wxLogin(Request $request)
{
$params = $request->all();
$url = sprintf(config('wx.wxLoginUrl'), config('wx.AppID'), config('wx.AppSecret'), $params['code']);
$client = new Client(['timeout' => 5, 'verify' => false]);
$response = $client->get($url);
$data = (string)$response->getBody();
$data = json_decode($data, true);
$renting = Renting::where('openid', $data['openid'])
->first();
if (empty($renting)) {
$renting = Renting::create(['openid'=>$data['openid']]);
}
$token = $renting->createToken('api')->accessToken;
Cache::set($token, $renting, 7200);
return response()->json(['errorCode' => 0, 'data' => ['token' => $token, 'expire' => 7200,'time'=>time()], 'msg' => '登录成功'],200);
}
public function saveUsers(Request $request)
{
$params = $request->all();
$token = explode(' ',$request->header('authorization'))[1];
$userInfo = Cache::get($token);
$userInfo->update($params);
return response()->json(['errorCode' => 0, 'data' => '', 'msg' => '修改成功']);
}
}
商品控制器
<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use App\Models\Goods;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Redis;
use App\Models\ActivityGoods;
use Illuminate\Support\Facades\Cache;
class GoodsController extends Controller
{
public function activityList()
{
$result = ActivityGoods::with(['goods'])
->get();
return response()->json(['errorCode' => 0, 'data' => $result, 'msg' => '查询成功']);
}
public function goodsDetail(Request $request)
{
$goods_id = $request->get('goods_id');
$result = ActivityGoods::with(['goods'])
->where('goods_id',$goods_id)
->first();
return response()->json(['errorCode' => 0, 'data' => $result, 'msg' => '查询成功']);
}
public function syncStock()
{
$result = ActivityGoods::with(['goods'])
->get()->toArray();
foreach ($result as $val){
$goods = "activity_goods_".$val['goods_id'];
for ($i=0; $i < $val['sku_nums']; $i++) {
Redis::lpush($goods, 1);
}
}
}
public function checkStock(Request $request)
{
$token = explode(' ',$request->header('authorization'))[1];
$userInfo = Cache::get($token);
$userID = $userInfo->id;
$goodsID = $request->input("goods_id");
$goods = "activity_goods_".$goodsID;
$robSuccessUser = "success_user".$goodsID;
$result = Redis::sismember($robSuccessUser,$userID);
if ($result) {
return response()->json(['errorCode' => 20000, 'data' => '', 'msg' => '已经抢购过了']);
}
$count = Redis::lpop($goods);
if (!$count) {
return response()->json(['errorCode' => 20001, 'data' => '', 'msg' => '已经抢光了哦']);
}
$success = Redis::sadd($robSuccessUser, $userID);
if(!$success){
Redis::lpush($goods, 1);
return response()->json(['errorCode' => 20002, 'data' => '', 'msg' => '已经抢购过了']);
}
return response()->json(['errorCode' => 0, 'data' => '', 'msg' => '秒杀成功']);
}
public function createOrder(Request $request)
{
$token = explode(' ',$request->header('authorization'))[1];
$userInfo = Cache::get($token);
$userID = $userInfo->id;
$goodsID = $request->input("goods_id");
$robSuccessUser = "success_user".$goodsID;
$result = Redis::sismember($robSuccessUser,$userID);
if (!$result) {
return response()->json(['errorCode' => 20003, 'data' => '', 'msg' => '手慢了!']);
}
DB::beginTransaction();
try{
$goodsID = (int)$goodsID;
$Act=ActivityGoods::find($goodsID);
$Act->sku_nums=$Act->sku_nums-1;
$Act->save();
$goodsID = (int)$goodsID;
$data=Goods::find($goodsID);
$data->goods_nums=$data->goods_nums-1;
$data->save();
$data=MD5(123);
DB::commit();
return response()->json(['errorCode' => 0, 'data' => $data, 'msg' => '下单成功!']);
}catch (\Exception $e){
DB::rollBack();
}
}
}
模型配置
用户modek
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Laravel\Passport\HasApiTokens;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Foundation\Auth\User as AuthUser;
class Renting extends AuthUser
{
use HasApiTokens,SoftDeletes;
protected $guarded = [];
protected $dates = ['deleted_at'];
}
秒杀model
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class ActivityGoods extends Model
{
use SoftDeletes;
protected $guarded = [];
protected $dates = ['deleted_at'];
public function goods()
{
return $this->belongsTo(Goods::class,'goods_id');
}
}
goods_model
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class Goods extends Model
{
use SoftDeletes;
protected $guarded = [];
protected $dates = ['deleted_at'];
}
小程序前台
自动登录

App({
onLaunch() {
let token = wx.getStorageSync('token')
let token_expire = wx.getStorageSync('token_expire')
let now_time = Math.round(new Date().getTime() / 1000).toString();
let expire_time = token_expire - now_time;
if (expire_time <= 0) {
wx.clearStorageSync('token')
wx.clearStorageSync('token_expire')
}
if (!token) {
wx.login({
success: res => {
let code = res.code
wx.request({
url: 'http://www.lianxi.com/api/v1/wx_login',
method: 'POST',
data: {
code
},
success: res => {
let token = res.data.data.token;
wx.setStorageSync('token', token)
wx.setStorageSync('token_expire', res.data.data.time + res.data.data.expire - 100)
}
})
}
})
}
},
globalData: {
userInfo: null
}
})
全局配置

const formatTime = date => {
const year = date.getFullYear()
const month = date.getMonth() + 1
const day = date.getDate()
const hour = date.getHours()
const minute = date.getMinutes()
const second = date.getSeconds()
return `${[year, month, day].map(formatNumber).join('/')} ${[hour, minute, second].map(formatNumber).join(':')}`
}
const formatNumber = n => {
n = n.toString()
return n[1] ? n : `0${n}`
}
export const debounce = (fn, interval)=>{
var timer;
var gapTime = interval || 1000;
return function() {
clearTimeout(timer);
var context = this;
var args = arguments;
timer = setTimeout(function() {
fn.call(context,args);
}, gapTime);
};
}
module.exports = {
formatTime,debounce
}
app.json
{
"pages":[
"pages/index/index",
"pages/goods_detail/goods_detail",
"pages/my/my",
"pages/order/order",
"pages/login/login",
"pages/logs/logs"
],
"window":{
"backgroundTextStyle":"light",
"navigationBarBackgroundColor": "#fff",
"navigationBarTitleText": "Weixin",
"navigationBarTextStyle":"black"
},
"tabBar": {
"list": [{
"pagePath": "pages/index/index",
"text": "首页"
}, {
"pagePath": "pages/my/my",
"text": "我的"
}]
},
"usingComponents": {
"l-card":"/miniprogram_npm/lin-ui/card",
"l-button":"/miniprogram_npm/lin-ui/button"
},
"style": "v2",
"sitemapLocation": "sitemap.json"
}
我的
授权登录
js
Page({
data: {
avatarIcon: 'user',
},
onLoad: function (options) {
let userInfo = wx.getStorageSync('userInfo')
if (userInfo) {
this.setData({
...userInfo,
avatarIcon: ''
})
}
},
getUser() {
let userInfo = wx.getStorageSync('userInfo')
if(userInfo){
return
}
wx.getUserProfile({
desc: '用于完善会员资料',
success: (res) => {
wx.setStorageSync('userInfo', res.userInfo)
var token = wx.getStorageSync('token')
wx.request({
url: 'http://www.lianxi.com/api/v1/users',
method: 'PUT',
header: {
'Authorization':`Bearer ${token}`
},
data:{
'nickname':res.userInfo.nickName,
'avatar':res.userInfo.avatarUrl
},
success: res => {
console.log(res)
}
})
this.setData({
...res.userInfo,
avatarIcon: ''
})
}
})
}
})
my.json
{
"usingComponents": {
"l-button":"/miniprogram_npm/lin-ui/button",
"l-avatar":"/miniprogram_npm/lin-ui/avatar"
}
}
my.wxml
<!-- 点击头像进行授权登录 -->
<l-avatar src="{{ avatarUrl }}" l-class="avatar-bg" size="120" icon="{{ avatarIcon }}" icon-style="color:#5bf320" bindtap="getUser"/>
<view>
<text>昵称:{{nickName}}</text>
</view>
首页
秒杀列表
index. js
const app = getApp()
Page({
data: {
goods:[]
},
onLoad: function (options) {
this.getActivityList();
},
getActivityList() {
var token = wx.getStorageSync('token')
wx.request({
url: 'http://www.lianxi.com/api/v1/activity_list',
header: {
'Authorization': `Bearer ${token}`
},
success: res => {
this.setData({
goods:res.data.data
})
}
})
}
})
index.json
{
"usingComponents": {
"l-card":"/miniprogram_npm/lin-ui/card",
"l-button":"/miniprogram_npm/lin-ui/button"
}
}
my.wxml
<block wx:for="{{ goods}}" wx:key="unique">
<l-card type="primary" full="{{true}}" image="{{item.goods.goods_image}}" title="{{ item.goods.goods_name}}">
<view>
价格:{{ item.goods.goods_price}}
</view>
<view>
<navigator url="/pages/goods_detail/goods_detail?goods_id={{ item.goods_id }}"> <l-button type="error">立即抢购</l-button></navigator>
</view>
</l-card>
</block>
index.wxss
.userinfo {
display: flex;
flex-direction: column;
align-items: center;
color: #aaa;
}
.userinfo-avatar {
overflow: hidden;
width: 128rpx;
height: 128rpx;
margin: 20rpx;
border-radius: 50%;
}
.usermotto {
margin-top: 200px;
}
秒杀详情
详情
goods_detail. js
import {
debounce
} from "../../utils/util"
Page({
data: {
goods:{},
expire_time:0,
btn_disable:false
},
onLoad: function (e) {
let goods_id = e.goods_id;
this.getGoodsDetail(goods_id)
},
getGoodsDetail(goods_id){
var token = wx.getStorageSync('token')
wx.request({
url: 'http://www.lianxi.com/api/v1/goods_detail?goods_id='+goods_id,
header: {
'Authorization': `Bearer ${token}`
},
success: res => {
let now_time = Math.round(new Date().getTime() / 1000).toString();
let expire_time = res.data.data.start_time - now_time;
this.setData({
goods:res.data.data,
expire_time
})
if(expire_time > 0){
this.setData({
btn_disable:true
})
}
console.log(this.data.goods)
}
})
},
buyGoods:debounce(function (e) {
let goods_id = e[0].currentTarget.dataset.goods_id
var token = wx.getStorageSync('token')
wx.request({
url: 'http://www.lianxi.com/api/v1/snap_up',
header: {
'Authorization': `Bearer ${token}`
},
method:"POST",
data:{
goods_id
},
success: res => {
let code = res.statusCode.toString()
if (!code.startsWith('2')){
wx.showToast({
title: '异常!',
icon:1
})
}
if(res.data.errorCode == 0){
wx.redirectTo({
url: '/pages/order/order?goods_id='+goods_id,
})
}else{
wx.showToast({
title: res.data.msg,
})
}
console.log(res.data)
}
})
}),
changeBtn(){
this.setData({
btn_disable:false
})
}
})
goods_detail. json
{
"usingComponents": {
"l-card":"/miniprogram_npm/lin-ui/card",
"l-button":"/miniprogram_npm/lin-ui/button",
"l-countdown":"/miniprogram_npm/lin-ui/countdown"
}
}```
#### goods_detail. wxss
```javascript
<view>商品秒杀页面</view>
<!-- 时间倒计时 -->
<l-countdown time-type="second" time="{{expire_time}}" bind:linend="changeBtn" />
<l-card type="primary" full="{{true}}" image="{{goods.goods.goods_image}}" title="{{goods.goods.goods_name}}">
<view>
价格:{{goods.goods.goods_price}}
</view>
<view>
<!-- <button disabled="true" bindtap="buyGoods" >抢购</button> -->
<l-button disabled="{{ btn_disable }}" bind:lintap="buyGoods" type="error" data-goods_id="{{ goods.goods.id }}">立即秒杀</l-button>
</view>
</l-card>
查看订单编号
订单编号
order. js
Page({
data: {
goods_id: 0,
dingdan:{}
},
onLoad: function (e) {
var goods_id = e.goods_id;
var token = wx.getStorageSync('token')
wx.request({
url: 'http://www.lianxi.com/api/v1/goods_order',
header: {
'Authorization': `Bearer ${token}`
},
method: "POST",
data: {
goods_id
},
success: res => {
let code = res.statusCode.toString()
if (!code.startsWith('2')){
wx.showToast({
title: '异常!',
icon:1
})
}
if(res.data.errorCode == 0){
this.setData({
dingdan:res.data.data
})
}
console.log(res.data.data)
}
})
},
.........
})
order. js
<view>抢购成功</view>
<view>订单编号:</view>
<view>{{dingdan}}</view>
|