登录中心功能开发
This commit is contained in:
@@ -8,6 +8,16 @@ use support\Request;
|
||||
|
||||
class AuthController extends BaseController
|
||||
{
|
||||
|
||||
public function feishuScope(Request $request)
|
||||
{
|
||||
try {
|
||||
$result = (new AuthService())->feishuAuthorize($request->corp_abbr, $request->system_code);
|
||||
return $this->success($result);
|
||||
} catch (\Throwable $e) {
|
||||
return $this->error($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function login(Request $request)
|
||||
{
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
|
||||
namespace app\common\controller;
|
||||
|
||||
use support\Request;
|
||||
use support\Response;
|
||||
use support\exception\BusinessException;
|
||||
use app\common\traits\ResponseTrait;
|
||||
use think\Validate;
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
namespace app\common\logic;
|
||||
|
||||
use app\common\model\Corp;
|
||||
use app\common\model\CorpFeishuApp;
|
||||
use app\common\model\UserTokenLog;
|
||||
use app\common\model\Systems;
|
||||
use app\common\model\User;
|
||||
@@ -375,6 +377,30 @@ class AuthLogic
|
||||
return $system;
|
||||
}
|
||||
|
||||
/**
|
||||
* 公司验证
|
||||
*/
|
||||
private function validateCorp(string $corpAbbr)
|
||||
{
|
||||
$corp = Corp::where('abbr', $corpAbbr)->first();
|
||||
if (!$corp) {
|
||||
throw new BusinessException('公司不存在', 403);
|
||||
}
|
||||
return $corp;
|
||||
}
|
||||
|
||||
/**
|
||||
* 飞书应用信息
|
||||
*/
|
||||
private function validateFeishuApp(int $corpId, string $systemCode)
|
||||
{
|
||||
$feishuAppInfo = CorpFeishuApp::where('corp_id', $corpId)->where('system_code', $systemCode)->first();
|
||||
if (!$feishuAppInfo) {
|
||||
throw new BusinessException('飞书应用不存在', 403);
|
||||
}
|
||||
return $feishuAppInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户系统权限校验
|
||||
*/
|
||||
@@ -450,6 +476,16 @@ class AuthLogic
|
||||
*/
|
||||
private function getFeishuUserInfo(string $code)
|
||||
{
|
||||
// // 获取凭证
|
||||
// $certificate = certificate($param['state']);
|
||||
// // 获取token
|
||||
// $class = new Feishu($certificate['appId'], $certificate['appSecre_s'], $param['state']);
|
||||
// $userAccessToken = $class->userAccessToken($param['code'], $certificate['rUrl']);
|
||||
// // 获取用户信息
|
||||
// $rst = $class->userInfo($userAccessToken['access_token']);
|
||||
// if ($rst['code'] != 0) {
|
||||
// throw new BusinessException('授权失败,请重试');
|
||||
// }
|
||||
// 实际实现需要调用飞书 API
|
||||
return [
|
||||
'user_id' => 'feishu_user_123',
|
||||
@@ -472,4 +508,20 @@ class AuthLogic
|
||||
}
|
||||
return $user;
|
||||
}
|
||||
|
||||
/**
|
||||
* 飞书应用信息
|
||||
*/
|
||||
public function feishuAppInfo(string $corpAbbr, string $systemCode)
|
||||
{
|
||||
$corpInfo = $this->validateCorp($corpAbbr);
|
||||
$fsAppInfo = $this->validateFeishuApp($corpInfo->id, $systemCode);
|
||||
return [
|
||||
'app_id' => $fsAppInfo->app_id,
|
||||
'app_secret' => $fsAppInfo->app_secret,
|
||||
'r_url' => $fsAppInfo->r_url,
|
||||
'scope' => $fsAppInfo->scopes,
|
||||
'state' => $fsAppInfo->state
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\model;
|
||||
|
||||
use support\Model;
|
||||
|
||||
/**
|
||||
* corp 企业-信息
|
||||
* @property integer $id ID(主键)
|
||||
* @property string $name 名称
|
||||
* @property string $abbr 缩写
|
||||
* @property string $tenant_key 飞书企业标识
|
||||
* @property integer $sort 排序
|
||||
* @property integer $status 状态
|
||||
* @property integer $created_at 创建时间
|
||||
* @property integer $updated_at 更新时间
|
||||
*/
|
||||
class Corp extends Model
|
||||
{
|
||||
/**
|
||||
* The connection name for the model.
|
||||
*
|
||||
* @var string|null
|
||||
*/
|
||||
protected $connection = 'mysql';
|
||||
|
||||
/**
|
||||
* The table associated with the model.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $table = 'corp';
|
||||
|
||||
/**
|
||||
* The primary key associated with the table.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $primaryKey = 'id';
|
||||
|
||||
/**
|
||||
* Indicates if the model should be timestamped.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $timestamps = true;
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\model;
|
||||
|
||||
use support\Model;
|
||||
|
||||
/**
|
||||
* corp_feishu_app 企业-飞书应用
|
||||
* @property integer $id ID(主键)
|
||||
* @property integer $corp_id 公司ID
|
||||
* @property string $name 名称
|
||||
* @property string $tenant_key 企业标识
|
||||
* @property string $app_id 应用ID
|
||||
* @property string $app_secret 应用秘钥
|
||||
* @property string $base_uri 基础域
|
||||
* @property string $r_url 授权地址
|
||||
* @property string $scopes 授权范围
|
||||
* @property string $state 携带参数
|
||||
* @property string $system_code 绑定系统码
|
||||
* @property integer $sort 排序
|
||||
* @property integer $status 状态
|
||||
* @property integer $created_at 创建时间
|
||||
* @property integer $updated_at 更新时间
|
||||
*/
|
||||
class CorpFeishuApp extends Model
|
||||
{
|
||||
/**
|
||||
* The connection name for the model.
|
||||
*
|
||||
* @var string|null
|
||||
*/
|
||||
protected $connection = 'mysql';
|
||||
|
||||
/**
|
||||
* The table associated with the model.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $table = 'corp_feishu_app';
|
||||
|
||||
/**
|
||||
* The primary key associated with the table.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $primaryKey = 'id';
|
||||
|
||||
/**
|
||||
* Indicates if the model should be timestamped.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $timestamps = true;
|
||||
|
||||
|
||||
}
|
||||
@@ -4,11 +4,20 @@ namespace app\common\service;
|
||||
|
||||
use app\common\logic\AuthLogic;
|
||||
use app\common\model\User;
|
||||
use app\common\utils\Feishu;
|
||||
use support\Db;
|
||||
|
||||
class AuthService
|
||||
{
|
||||
|
||||
/**
|
||||
* 飞书授权
|
||||
*/
|
||||
public function feishuAuthorize(string $corpAbbr, string $systemCcode)
|
||||
{
|
||||
return (new AuthLogic())->feishuAppInfo($corpAbbr, $systemCcode);
|
||||
}
|
||||
|
||||
/**
|
||||
* 登录,支持多类型
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,118 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\service;
|
||||
|
||||
use app\common\model\Corp;
|
||||
use app\common\model\Systems;
|
||||
use support\Redis;
|
||||
use support\exception\BusinessException;
|
||||
|
||||
class BasicDataService
|
||||
{
|
||||
/**
|
||||
* 检查并缓存独立的基础参数
|
||||
*/
|
||||
public function checkAndCacheBaseParams($loginType, $systemCode, $corpAbbr)
|
||||
{
|
||||
// 构造缓存键
|
||||
$loginTypeKey = 'login_type_' . $loginType;
|
||||
$systemCodeKey = 'system_code_' . $systemCode;
|
||||
$corpAbbrKey = 'corp_abbr_' . $corpAbbr;
|
||||
|
||||
// 检查缓存中是否有登录类型参数
|
||||
if (!$this->checkParamInCache($loginTypeKey, $loginType)) {
|
||||
// 如果 Redis 没有缓存,执行数据库查询并存入缓存
|
||||
$this->cacheLoginType($loginTypeKey, $loginType);
|
||||
}
|
||||
|
||||
// 检查缓存中是否有系统码参数
|
||||
if (!$this->checkParamInCache($systemCodeKey, $systemCode)) {
|
||||
// 如果 Redis 没有缓存,执行数据库查询并存入缓存
|
||||
$this->cacheSystemCode($systemCodeKey, $systemCode);
|
||||
}
|
||||
|
||||
// 检查缓存中是否有公司标识参数
|
||||
if (!$this->checkParamInCache($corpAbbrKey, $corpAbbr)) {
|
||||
// 如果 Redis 没有缓存,执行数据库查询并存入缓存
|
||||
$this->cacheCorpAbbr($corpAbbrKey, $corpAbbr);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查参数是否在 Redis 缓存中
|
||||
*/
|
||||
private function checkParamInCache($cacheKey, $param)
|
||||
{
|
||||
return Redis::get($cacheKey) === $param;
|
||||
}
|
||||
|
||||
/**
|
||||
* 缓存登录类型
|
||||
*/
|
||||
private function cacheLoginType($cacheKey, $loginType)
|
||||
{
|
||||
// 假设我们从数据库或其他来源验证 loginType 的合法性
|
||||
if (!$this->validateLoginType($loginType)) {
|
||||
throw new BusinessException('无效的登录方式');
|
||||
}
|
||||
// 存入缓存,缓存有效期可以根据需求调整
|
||||
Redis::setex($cacheKey, 3600, $loginType); // 1小时有效期
|
||||
}
|
||||
|
||||
/**
|
||||
* 缓存系统码
|
||||
*/
|
||||
private function cacheSystemCode($cacheKey, $systemCode)
|
||||
{
|
||||
// 假设我们从数据库或其他来源验证 systemCode 的合法性
|
||||
if (!$this->validateSystemCode($systemCode)) {
|
||||
throw new BusinessException('无效的系统码');
|
||||
}
|
||||
// 存入缓存,缓存有效期可以根据需求调整
|
||||
Redis::setex($cacheKey, 3600, $systemCode); // 1小时有效期
|
||||
}
|
||||
|
||||
/**
|
||||
* 缓存公司标识
|
||||
*/
|
||||
private function cacheCorpAbbr($cacheKey, $corpAbbr)
|
||||
{
|
||||
// 假设我们从数据库或其他来源验证 corpAbbr 的合法性
|
||||
if (!$this->validateCorpAbbr($corpAbbr)) {
|
||||
throw new BusinessException('无效的公司标识');
|
||||
}
|
||||
// 存入缓存,缓存有效期可以根据需求调整
|
||||
Redis::setex($cacheKey, 3600, $corpAbbr); // 1小时有效期
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证登录方式
|
||||
*/
|
||||
private function validateLoginType($loginType)
|
||||
{
|
||||
// 假设这里是验证登录方式的具体逻辑
|
||||
return in_array($loginType, ['upwd', 'feishu', 'qrcode']);
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证系统码
|
||||
*/
|
||||
private function validateSystemCode($systemCode)
|
||||
{
|
||||
// 假设这里是验证系统码的具体逻辑
|
||||
$system = Systems::where('code', $systemCode)->first();
|
||||
return $system !== null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证公司标识
|
||||
*/
|
||||
private function validateCorpAbbr($corpAbbr)
|
||||
{
|
||||
// 假设这里是验证公司标识的具体逻辑
|
||||
$company = Corp::where('abbr', $corpAbbr)->first();
|
||||
return $company !== null;
|
||||
}
|
||||
}
|
||||
@@ -19,7 +19,7 @@ trait ResponseTrait
|
||||
public function success(
|
||||
$data = [],
|
||||
string $message = '请求成功',
|
||||
int $code = 0,
|
||||
int $code = 200,
|
||||
int $httpStatus = 200,
|
||||
array $header = ['Content-Type' => 'application/json']
|
||||
): Response {
|
||||
@@ -38,7 +38,7 @@ trait ResponseTrait
|
||||
*/
|
||||
public function error(
|
||||
string $message = '请求失败',
|
||||
int $code = 1,
|
||||
int $code = 400,
|
||||
int $httpStatus = 400,
|
||||
$data = [],
|
||||
array $header = ['Content-Type' => 'application/json']
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace app\common\validate;
|
||||
|
||||
use app\common\model\Corp;
|
||||
use app\common\model\Systems;
|
||||
use app\common\model\User;
|
||||
use think\Validate;
|
||||
@@ -17,7 +18,8 @@ class UserValidate extends Validate
|
||||
'phone' => 'checkMobile|checkPhoneUnique',
|
||||
'email' => 'email|checkEmailUnique',
|
||||
'login_type' => 'require|in:upwd,feishu,qrcode',
|
||||
'system_code' => 'require|checkSystemCode'
|
||||
'system_code' => 'require|checkSystemCode',
|
||||
'corp_abbr' => 'require|checkCorpAbbr',
|
||||
];
|
||||
|
||||
protected $message = [
|
||||
@@ -40,12 +42,15 @@ class UserValidate extends Validate
|
||||
'login_type.require' => '请选择登录方式',
|
||||
'login_type.in' => '登录方式不支持',
|
||||
'system_code.require' => '系统码不能为空',
|
||||
'system_code.checkSystemCode' => '系统码不存在或不合法'
|
||||
'system_code.checkSystemCode' => '系统码不存在或不合法',
|
||||
'corp_abbr.require' => '公司标识不能为空',
|
||||
'corp_abbr.checkCorpAbbr' => '公司标识不存在或不合法'
|
||||
];
|
||||
|
||||
protected $scene = [
|
||||
'upwd_register' => ['name', 'account', 'password', 'confirm_password', 'login_type', 'system_code'],
|
||||
'upwd_login' => ['account', 'password', 'login_type', 'system_code'],
|
||||
'feishu_auth' => ['corp_abbr', 'system_code', 'login_type']
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -129,4 +134,12 @@ class UserValidate extends Validate
|
||||
{
|
||||
return Systems::where('code', $value)->exists();
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证 corp_abbr 企业标识是否存在
|
||||
*/
|
||||
protected function checkCorpAbbr($value, $rule, $data, $field)
|
||||
{
|
||||
return Corp::where('abbr', $value)->exists();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
namespace app\middleware;
|
||||
|
||||
use Webman\MiddlewareInterface;
|
||||
use Webman\Http\Response;
|
||||
use Webman\Http\Request;
|
||||
|
||||
class AccessControl implements MiddlewareInterface
|
||||
{
|
||||
public function process(Request $request, callable $handler) : Response
|
||||
{
|
||||
// 如果是options请求则返回一个空响应,否则继续向洋葱芯穿越,并得到一个响应
|
||||
$response = $request->method() == 'OPTIONS' ? response('') : $handler($request);
|
||||
|
||||
// 给响应添加跨域相关的http头
|
||||
$response->withHeaders([
|
||||
'Access-Control-Allow-Credentials' => 'true',
|
||||
'Access-Control-Allow-Origin' => $request->header('origin', '*'),
|
||||
'Access-Control-Allow-Methods' => $request->header('access-control-request-method', '*'),
|
||||
'Access-Control-Allow-Headers' => $request->header('access-control-request-headers', '*'),
|
||||
]);
|
||||
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
namespace app\middleware;
|
||||
|
||||
use Webman\MiddlewareInterface;
|
||||
use Webman\Http\Response;
|
||||
use Webman\Http\Request;
|
||||
use app\common\service\BasicDataService;
|
||||
|
||||
class BasicDataMiddleware implements MiddlewareInterface
|
||||
{
|
||||
|
||||
public function process(Request $request, callable $next): Response
|
||||
{
|
||||
try {
|
||||
$loginType = $request->header('login_type');
|
||||
$systemCode = $request->header('system_code');
|
||||
$corpAbbr = $request->header('corp_abbr');
|
||||
$basicDataService = new BasicDataService();
|
||||
if ($basicDataService->checkAndCacheBaseParams($loginType, $systemCode, $corpAbbr)) {
|
||||
$request->login_type = $loginType;
|
||||
$request->system_code = $systemCode;
|
||||
$request->corp_abbr = $corpAbbr;
|
||||
}
|
||||
return $next($request);
|
||||
} catch (\Throwable $th) {
|
||||
throw $th;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -12,4 +12,8 @@
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
return [];
|
||||
return [
|
||||
'' => [
|
||||
\app\middleware\BasicDataMiddleware::class
|
||||
]
|
||||
];
|
||||
@@ -30,5 +30,6 @@ Route::group('/common', function () {
|
||||
Route::group('/auth', function () {
|
||||
Route::post('/login', [app\common\controller\AuthController::class, 'login']);
|
||||
Route::post('/register', [app\common\controller\AuthController::class, 'register']);
|
||||
Route::post('/feishu/scope', [app\common\controller\AuthController::class, 'feishuScope']);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user