很久很久以前,第三方授权登录就开始流行。比如 qq、微博、github、微信这些。如果有一个大的平台来做这个服务的确是很方便的一个事情。在这些授权后都会有一个回调页面,就是从自己的网页跳转到授权页面,再跳转回来。但是,小程序是没提供这个服务的。但是自己可以构造类似的方式。
整个环节,代码都是由自己控制,可以很灵活的视线需求。仅仅是生成小程序码和扫码登录上小程序是腾讯那边做的。
示例:https://www.zeipan.com/admin

步骤
关键点:这里以 jwt 的认证方式来实现授权登录。
- 登录页获取并展示生成携带参数的小程序码
- 登录页面轮询获取登录状态(这里是 token)
- 手机微信扫描小程序码并授权同意登录
该后台使用 vite + ts + pnpm + vue3 + element-plus + tailwindcss 等技术栈构成。没有添加任意可视化图标等插件。以最小功能,最基础功能展现。用户可以额外添加可使用的插件逻辑。
该后台后端使用 php8.2 + laravel 10 + mysql
该后台后端 go 语言版本开发中。将使用 gframe2.5.2
源码: https://github.com/vini123/simpleAdmin
在线体验: https://www.zeipan.com/admin
权限以及密码一键复位: https://v3test.yuepaibao.com/admin/api/reset
测试账号以及密码: zhoulin@xiangrong.pro、 111111 (如果发现登录不了,可一键复位谢谢)

既然 go 的迁移、seeder 等不好用,还是用 laravel 来搞吧。
开始
composer create-project laravel/laravel youme.com --prefer-dist
这样就创建了一个最新的 laravel 项目,项目文件在 youme.com 里。在本地,做了 host 映射。通过 youme.com 就可以打开。

上边就是默认的。
创建 git 版本控制,提交。
git init -b main
git add .
git commit -m 'laravel initialize'
前端本地测试,mock 可以先用着。终究还是得和真实的服务环境对接。这个时候请求接口,往往就会遇到跨域的问题。对于 laravel框架,对于 laravel10,只需要建立一个中间件,在中间件中对请求进行处理就好。需要的时候,带上中间件,不需要的时候,去掉它就可以。还是很方便的。
Do
php artisan make:middleware EnableCrossRequestMiddleware
# 完整代码如下
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
class EnableCrossRequestMiddleware
{
/**
* Handle an incoming request.
*
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
*/
public function handle(Request $request, Closure $next): Response
{
$response = $next($request);
$origin = $request->server('HTTP_ORIGIN') ? $request->server('HTTP_ORIGIN') : '';
$allow_origin = [
'http://localhost:5173',
];
if (in_array($origin, $allow_origin)) {
$IlluminateResponse = 'Illuminate\Http\Response';
$SymfonyResopnse = 'Symfony\Component\HttpFoundation\Response';
$headers = [
'Access-Control-Allow-Origin' => $origin,
'Access-Control-Allow-Methods' => 'POST,GET,OPTIONS,PUT,PATCH,DELETE',
'Access-Control-Allow-Headers' => 'Accept,Content-Type,Referer,User-Agent,Origin,X-Requested-With,X-XSRF-TOKEN,X-CSRF-TOKEN,Authorization,Time'
];
if ($response instanceof $IlluminateResponse) {
foreach ($headers as $key => $value) {
$response->header($key, $value);
}
return $response;
}
if ($response instanceof $SymfonyResopnse) {
foreach ($headers as $key => $value) {
$response->headers->set($key, $value);
}
return $response;
}
}
return $response;
}
}
然后,在 ./app/Http/Kernel.php 的 $middleware 中添加一个配置。
protected $middleware = [
…
\App\Http\Middleware\EnableCrossRequestMiddleware::class,
];
这样就完事了。
本来是想将中间件放在中间件组里(middlewareGroups)或使用 alias (放在 $middlewareAliases)的方式来使用,但都失败了。暂时还没找到原因。
之所以想这样弄,是因为不是所有的请求都需要设置请求头。
Please use another name or delete the machine with the existing name, and try again
A VirtualBox machine with the name 'homestead' already exists.
Please use another name or delete the machine with the existing
name, and try again.
Do
之前在mac上安装laravel/homestead vagrant虚拟机环境时由于参照的教程是: 每次都必须在~/Homestead目录下边运行vagrant up/halt命令,觉得实在是不方便,于是乎按照另外一个教程(在任何目录下可以通过homestead up来启动虚拟机)来配置环境,但是当键入homestead up时,却报出
==> default: Importing base box 'laravel/homestead'...
==> default: Matching MAC address for NAT networking...
A VirtualBox machine with the name 'homestead' already exists.
Please use another name or delete the machine with the existing
name, and try again.
这样的错误
stackoverflow上好几个人说通过vagrant global-status 查看虚拟器,然后在vagrant destroy {id}删除对应名称的虚拟机可以解决问题,但是重复n遍homestead up或者到~/Homestead下运行vagrant up之后,还是会报出上边的错误,后来通过VBoxManage list vms获取虚拟机列表,然后在通过运行
VBoxManage unregistervm homestead --delete
之后,重新运行homestead up之后 一切回归正常
参考
# 在 mysql 中,先查询出 sql_mode
show variables like 'sql_mode';
# 编辑修改
sudo vim /etc/mysql/mysql.conf.d/mysqld.cnf
# 没有就追加,有就修改
# 先备份一个全的
# sql_mode=ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION
sql_mode =这里你填需要的
# 重启
sudo service mysql restart
https://learnku.com/docs/laravel/10.x/octane/14909#swoole
https://segmentfault.com/a/1190000040673969
https://chriswhite.is/coding/swoole-vs-roadrunner-for-laravel-octane/
composer require laravel/octane
# 选择 swoole
php artisan octane:install
# 安装 swoole
pecl install swoole
# 查找 php.ini 文件位置
php -i grep | php.ini
# vim 编辑,并配置
extension=swoole.so
# 重启 php
sudo /etc/init.d/php-fpm restart
# 查看扩展
php -i |grep swoole
laravel orm 的多态有的时候是真的好用。比如,我们在设计一个消息表的时候,这个多态就很有用。消息对于整个项目,是一个基础的统称。比如,有人注册账号了,给他一个欢迎的消息。 有人充值了一个会员,给他一个充值消息。有人参加了一个活动,给他一个参加的消息。就这样一个场景。在消息表里边,我们仅仅需要构建这些字段
user_id、content、messageable_id、messageable_type、status、updated_at、created_at
就可以了。是不是很干净,是不是很舒适。后端的东西往往是给前端服务的。我们要会联想到前端的一个场景。有一个消息列表,我们点击消息,应该可以查看到消息的详情。比如会员消息详情、充值详情(当然有的时候是不需要详情,比如欢迎语。)这个时候,多态一对一在这个场景就很符合。这个多态和面向对象里的多态(继承、接口)不一样,但有相似的意境。
开始
多态的重要信息是 xxxable_id、和 xxxable_type。一个对应的是目标对象的 id,一个对应的是目标对象的类名(比如 App\Models\Topic)。
在 xxx 模型中。我们要定义一个 xxxable 方法。这里以 Message 模型为例。
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\MorphTo;
class Message extends Model
{
use HasFactory;
protected $fillable = ['user_id', 'content', 'messageable_id', 'messageable_type'];
public function user()
{
return $this->belongsTo(User::class);
}
/**
* 获取父级的对象
*/
public function messageable(): MorphTo
{
return $this->morphTo();
}
}
在父级对象中,你也可以定义相对应的关系。当然也可以不定义。在这个场景中,我们重要的是消息列表以及消息对应的对象。所以仅仅在消息中定义 morph 就好。
使用
比如: Message::query()->take(10)->with('messageable')->get();
一个完整的过程。我们有这三个模型:Message(消息)、Topic(话题)、Member(会员)。
$user = $request->user();
$data = [xxx];
$topic = Topic::create($data);
# 获取类名
$topicClass = get_class($topic);
# 创建消息
Message::create([
'user_id' => $user->id,
'content' => '您的话题已创建,请等待审核',
'messageable_id' => $topic->id,
'messageable_type' => $topicClass
]);
---------------------------------------
$member = Member::create($data);
Message::create([
'user_id' => $user->id,
'content' => '您已成为会员,请愉快的玩耍吧',
'messageable_id' => $member->id,
'messageable_type' => get_class($member)
]);
再啰嗦一点点
上边说了,前端是要点击消息,做对应的跳转的。既然后端是动态绑定(多态算是动态的一种绑定吧),那么前端就是一个强制的硬性的绑定了,可以理解为是枚举。可以用 if 来搞定。因为消息的种类就那么多,不像数据库,有成千上万百万千万的数据。
if (消息类型一) {
跳转到一
} else if (消息类型二) {
跳转到二
}
因为有了 messageable_id,我们就可以通过接口来请求各自所想要的信息了。
对于消息列表。如果没有特殊的要求 messageable
我们也是不需要在这里就请求上的。因为请求了,就需要数据库去查询。查询了又不用,那不是浪费。这里看具体情况哈。
中文文档
https://learnku.com/docs/laravel/10.x/eloquent-relationshipsmd/14889#5981a6
虽然有 docker , 但还是喜欢用 homestead 开发环境。这个时候,一些旧的项目可能会用到比较低版本的 php,这个时候切换 php 版本就是一个常用的操作。
使用 php 版本
homestead 环境中,项目使用 php 的哪个版本,可以在 Homestead.yaml 文件中进行配置。比如:
sites:
- map: work.xiangrong.com
to: /home/vagrant/code/zhoulin/work.xiangrong.com/public
php: "7.4"
这里指定好 php 版本就好。
但是,当 homestead
环境中当前使用的 php
版本是 php 8
或 php 5.6
这些。使用 composer
或项目本身就有可能报错。这个时候,我们就需要将 homestead
环境的 php
版本切换的和项目所配置的一样。
补充
如果切换成对应的 php 版本还会出 badgateway
这样的错误,可以试着重启 php 看看。
# 这里以 php 7.4 为例
sudo /etc/init.d/php7.4-fpm restart
操作
# 查看当前环境中的 php 版本
php -v

# 查看所有 php 版本和当前版本
sudo update-alternatives --display php

# 执行后,会列出当前 php 所有版本和编号,输入编号,切换到执行的版本
sudo update-alternatives --config php

其实
其实,想切换到某个 php 版本。直接输入就可以了,也不用向上边那样敲那么长的命令。 比如,想切换到 php7.4 版本。直接输入 php74 回车即可。同理,想切换到 php8.2 版本,直接输入 php82 回车即可。这些命令,可以在 Homestead 目录下的 aliases 文件中找到。
function php73() {
sudo update-alternatives --set php /usr/bin/php7.3
sudo update-alternatives --set php-config /usr/bin/php-config7.3
sudo update-alternatives --set phpize /usr/bin/phpize7.3
}
function php74() {
sudo update-alternatives --set php /usr/bin/php7.4
sudo update-alternatives --set php-config /usr/bin/php-config7.4
sudo update-alternatives --set phpize /usr/bin/phpize7.4
}
function php80() {
sudo update-alternatives --set php /usr/bin/php8.0
sudo update-alternatives --set php-config /usr/bin/php-config8.0
sudo update-alternatives --set phpize /usr/bin/phpize8.0
}
function php81() {
sudo update-alternatives --set php /usr/bin/php8.1
sudo update-alternatives --set php-config /usr/bin/php-config8.1
sudo update-alternatives --set phpize /usr/bin/phpize8.1
}
function php82() {
sudo update-alternatives --set php /usr/bin/php8.2
sudo update-alternatives --set php-config /usr/bin/php-config8.2
sudo update-alternatives --set phpize /usr/bin/phpize8.2
}
今天五月一日。