Skip to content

移动应用端 API 开发指南

CatchAdmin 专业版已提供完整的后台管理系统,现新增移动应用端开发解决方案。app 应用端专为前端移动应用和 Web 应用提供标准化 API 接口服务,支持快速构建现代化应用程序。核心功能包括

  • 基于 JWT 的用户认证
  • 统一的枚举管理
  • 统一的响应处理
  • 统一异常渲染处理
  • 身份认证中间件

为了帮助开发者快速掌握 CatchAdmin 专业版 app 应用端的标准化开发架构,本文将详细介绍每个功能模块的实现方法和最佳实践,建议在开始 API 开发前完整阅读

INFO

移动应用端 API 路由统一使用 api/app 前缀,可通过 php artisan route:list | grep api/app 命令查看所有可用接口

WARNING

移动应用端采用独立架构设计,与后台管理系统在业务逻辑上完全分离,仅在数据模型层共享。应用端通过调用各模块的 Eloquent 模型来实现数据访问。

如需更规范的数据访问层管理,建议在 app 应用中引入仓库模式(Repository Pattern)。

JWT 用户认证系统

CatchAdmin 专业版移动应用端采用 JWT(JSON Web Token)作为身份认证解决方案。相比后台管理使用的 Laravel Sanctum,JWT 更适合移动端和分布式应用场景,主要优势包括

  • santum 一次身份正常需要查询两次,JWT 只有一次
  • JWT 的 Claim 可以承载更多的信息,无需回表。sanctum 需要从数据库查询
  • sanctum 只适合单体应用,JWT 兼容单体,并支持分布式架构

基于性能和扩展性考虑,在高并发移动应用场景下,JWT 认证方案具有明显的性能优势和更好的横向扩展能力,因此 CatchAdmin 专业版应用端选择 JWT 作为标准身份认证方案。

安装

CatchAdmin 专业版 3.2.0+ 版本内置 JWT 认证支持,无需额外配置。低于此版本需要手动安装 JWT 扩展包

WARNING

请确认 CatchAdmin 专业版版本:< 3.2.0 需要执行以下安装步骤,>= 3.2.0 版本可跳过此节。

shell
composer require "tymon/jwt-auth"

然后发布 jwt 配置文件

shell
php artisan vendor:publish --provider="Tymon\JWTAuth\Providers\LaravelServiceProvider"

再生成 jwt 密钥

shell
php artisan jwt:secret

JWT 配置请查看配置文件 config/jwt.php

路由

移动应用端当前提供基础的用户认证 API 接口:登录登出。完整路由配置位于 routes/api.php 文件

php
Route::prefix('app')->group(function (){
    // 登录
    Route::post('login', [AuthController::class, 'login']);
    // 登出
    Route::post('logout', [AuthController::class, 'logout'])->middleware('auth:app');
});

auth 配置

config/auth.php 配置文件中,针对移动应用端的身份认证守卫(Guard)配置如下

php
return [
    'guards' => [
        // 前台 app 接口认证
        'app' => [
            'driver' => 'jwt',
            'provider' => 'app_users',
        ]
    ],


    'providers' => [
        // 前台用户模型
        'app_users' => [
            'driver' => 'eloquent',
            'model' => \Modules\Member\Models\Members::class // 使用会员表
        ],
    ],
];

认证代码

移动应用端支持多种身份认证方式:密码登录微信小程序登录小程序手机号快捷登录。认证控制器位于 app/Http/Controllers/AuthController.php,基于 Laravel Auth 门面实现标准化身份验证流程

php
use App\Services\Auth\UserService;

class AuthController extends Controller
{
   /**
     * 登录
     *
     * @param Request $request
     * @param UserService $service
     * @return JsonResponse
     */
    public function login(Request $request, UserService $service): JsonResponse
    {
        // 系统封装了 UserService 用于处理用户登录
        $user = $service->setAdapterType($request->get('type'))->auth($request->all());

        if (! $user) {
            throw new UnauthorizedAccessException();
        }

        return $this->success($user);
    }

    /**
     * @return JsonResponse
     */
    public function logout(): JsonResponse
    {
        // 退出之后将 token 加入黑名单
        $this->appGuard()->logout(true);

        return ApiResponse::success();
    }
}

用户认证服务的核心实现逻辑,请参考 app/Services/Auth/UserService.php 认证服务类

php
 /* @var Login $loginAdapter */
$loginAdapter = app($this->getLoginAdapter($this->type));

if ($res = $loginAdapter->auth($params)) {
    [$user, $token] = $res;

    $user->rememberToken($token);

    return $user->makeHidden([
        'password', 'from', 'creator_id'
    ]);
}

return false;

对应的三种登录方式代码

php
//  app/Services/Auth/PasswordLogin.php

// 自动识别登录账号类型:手机号格式则使用 mobile 字段,否则使用 username 字段
$field = preg_match('/^1[0123456789]\d{10}$/', $params['account']) ? 'mobile' : 'username';

// Auth 认证
$token = Auth::guard('app')->attempt([
    $field => $params['account'],
    'password' => $params['password'],
]);

if ($token) {
    return [Auth::guard('app')->user(), $token];
}

return false;
php
// app/Services/Auth/WechatLogin.php
try {
    // 通过微信小程序 code 换取 session_key 和 openid
    $response = $this->getMiniAppApplication()->getUtils()->codeToSession($params['code']);

    $user = $this->getAuthModel()->firstOrCreate([
        'miniapp_openid' => $response['openid'],
    ],[
        'username' => $params['username'],
        'from' => 'miniprogram',
        'miniapp_openid' => $response['openid'],
        'avatar' => $this->storeAvatar(),
        'mobile' => '',
        'created_at' => time(),
        'last_login_at' => time(),
        'updated_at' => time(),
    ]);

    if (! $user) {
        return false;
    }

    return [$user, JWTAuth::fromUser($user)];
} catch (\Throwable $e) {
    throw new UnauthorizedAccessException();
}
php
// app/Services/Auth/WechatByMobileLogin.php
try {
    // 获取微信小程序用户的 openid
    $openid = $this->getMiniAppOpenId($params['code']);
    // 检查是否已存在该 openid 的用户记录
    $user = $this->getAuthModel()->where('miniapp_openid', $openid)->first();
    if ($user) {
        $user->username = $params['username'];
        $user->mobile = $this->getMiniAppUserMobile($params['phoneCode']);
        $user->avatar = $this->storeAvatar();
        $user->last_login_at = time();
        $user->updated_at = time();
        $user->save();
    } else {
        $user = $this->getAuthModel()->firstOrCreate([
            'mobile' => $this->getMiniAppUserMobile($params['phoneCode']),
        ], [
            'username' => $params['username'],
            'from' => 'miniprogram',
            'avatar' => $this->storeAvatar(),
            'miniapp_openid' => $openid,
            'created_at' => time(),
            'last_login_at' => time(),
            'updated_at' => time(),
        ]);
    }

    if (! $user) {
        return false;
    }

    return [$user, JWTAuth::fromUser($user)];
} catch (\Throwable $e) {
    throw new UnauthorizedAccessException();
}

API 认证中间件配置

移动应用端身份认证中间件实现位于 app/Http/Middleware/AuthMiddleware.php,负责验证 JWT Token 有效性

php
class AuthMiddleware
{
    /**
     * Handle an incoming request.
     *
     * @param  \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response)  $next
     */
    public function handle(Request $request, Closure $next, string $guard): Response
    {
        if (! $request->bearerToken()) {
            throw new TokenMissedException();
        }

        $user = Auth::guard($guard)->user();

        if (! $user) {
            throw new AuthenticationException();
        }

        return $next($request);
    }
}

中间件别名

为简化中间件调用,为认证中间件配置别名。在 bootstrap/app.php 文件中注册中间件别名

php
// 在 bootstrap/app.php 文件中注册中间件别名
->withMiddleware(function (Middleware $middleware) {
    //
    $middleware->alias([
        // 注册认证中间件别名,支持多种守卫:auth:app(移动端)、auth:web(后台)等
        'auth' => AuthMiddleware::class
    ]);
})

认证中间件通过 Laravel Auth 门面实现多守卫支持,只需传入对应的守卫名称 $guard 参数。移动应用端需要身份认证的路由配置示例

php
// 使用 auth:app 中间件,指定使用移动应用端的 JWT 认证守卫
Route::post('logout', [AuthController::class, 'logout'])->middleware('auth:app');

响应码枚举管理

移动应用端所有枚举类统一管理在 App\Enums 目录下,提供类型安全的常量定义。当前内置枚举包括

  • Enum 枚举接口
  • Code 项目自带的响应码枚举

WARNING

移动应用端开发规范:所有自定义枚举类必须实现 Enum 接口,确保代码的一致性和可维护性。

下面是 Code 枚举的具体实现,对于响应的数据的 code 可以根据实际需求重新修改

php
/**
 * API 响应状态码枚举 - 统一管理移动应用端响应代码
 */
enum Code:int implements Enum
{
    case SUCCESS = 10000;
    case FAILED = 10001;
    case LOGIN_FAILED = 10002;
    case AUTH_EXCEPTION = 10003;
    case TOKEN_EXPIRED = 10004;
    case TOKEN_INVALID = 10005;
    case TOKEN_BLACKLIST = 10006;
    case TOKEN_MISSED = 10007;

    /**
     * @return string
     */
    public function message(): string
    {
        return match ($this) {
            self::SUCCESS => 'success',
            self::FAILED => 'failed',
            self::LOGIN_FAILED => '登录失败',
            self::AUTH_EXCEPTION => '认证失败',
            self::TOKEN_EXPIRED => 'token 过期',
            self::TOKEN_INVALID => 'token 无效',
            self::TOKEN_BLACKLIST => 'token 黑名单',
            self::TOKEN_MISSED => 'token 丢失',
        };
    }


    /**
     * @param mixed $value
     * @return bool
     */
    public function equal(mixed $value): bool
    {
        return $this->value === $value;
    }
}

API 响应格式规范

移动应用端提供统一的 API 响应格式处理类,确保客户端接收到一致的数据结构。可根据项目需求自定义响应格式

php
/**
 * 移动应用端统一 API 响应处理类
 * 确保所有接口返回一致的数据格式
 */
class ApiResponse
{
    /**
     * 成功响应 - 标准成功数据格式
     */
    public static function success(mixed $data = [], string $message = 'success', Code $code = Code::SUCCESS): JsonResponse
    {
        return response()->json([
            'code' => $code->value,
            'message' => $message,
            'data' => $data,
        ]);
    }

    /**
     * 错误响应 - 标准错误信息格式
     */
    public static function error(string $message = 'api error', int|Code $code = Code::FAILED): JsonResponse
    {
        return response()->json([
            'code' => $code instanceof Enum ? $code->value : $code,
            'message' => $message,
        ]);
    }

    /**
     * 分页响应 - 列表数据分页格式
     */
    public static function paginate(LengthAwarePaginator $paginator, string $message = 'success', Code $code = Code::SUCCESS): JsonResponse
    {
        return response()->json([
            'code' => $code->value,
            'message' => $message,
            'data' => $paginator->items(),
            'total' => $paginator->total(),
            'limit' => $paginator->perPage(),
            'page' => $paginator->currentPage(),
        ]);
    }
}

API 异常处理机制

移动应用端在 App\Exceptions 目录下提供完整的异常处理机制,支持类型化异常管理和统一错误响应。内置异常类型包括

  • AuthenticationException 身份认证异常
  • FailedException 通用的失败异常
  • TokenMissedException token 修饰异常
  • UnauthorizedAccessException 登录授权异常

为实现移动应用端异常的统一处理和响应格式标准化,所有自定义异常类必须继承 ApiAppException 基类

php
abstract class ApiAppException extends HttpException
{
    //
    public function __construct(
        string $message = '',
        Code $code = Code::FAILED
    ) {
        // 异常所有的 code 都使用枚举值,那么只需要维护 Code 枚举类就可以了
        if ($this->code instanceof Enum) {
            $code = $this->code;

            $this->message = $this->code->message();
        }

        parent::__construct(
            $this->statusCode(),
            $message ?: $this->message,
            null,
            [],
            $code->value
        );
    }

    /**
     * @return int
     */
    protected function statusCode(): int
    {
        return 500;
    }
}

例如 AuthenticationException 异常,只需要这么定义就可以了

php
use App\Enums\Code;

class AuthenticationException extends ApiAppException
{
    protected $code = Code::AUTH_EXCEPTION;
}

通过枚举类统一管理异常代码和错误信息,实现了异常处理的类型安全和维护便利性。

统一异常处理

为确保移动应用端获得一致的 JSON 格式错误响应,需要配置全局异常处理器。在 bootstrap/app.php 文件的 withExceptions 方法中配置

php
 ->withExceptions(function (Exceptions $exceptions) {
    $exceptions->render(function (Throwable $exception, Request $request) {
        // 渲染 app 异常,返回错误信息
        if ($exception instanceof ApiAppException) {
            return ApiResponse::error($exception->getMessage(), $exception->getCode());
        }
        // 其他系统异常自行处理, 请根据项目实际情况进行处理
        // 如果路由前缀使用 api/app 则返回 api app 异常
        if ($request->route()->prefix('api/app')) {
            return ApiResponse::error($exception->getMessage(), $exception->getCode());
        }
    });
})

API 路由组织结构

移动应用端 API 路由按照认证需求进行分组管理,将公开接口和需要身份认证的接口分别组织。在 routes/api.php 中按以下结构配置

php
// 移动应用端 API 路由组织 - 按认证需求分组管理
Route::prefix('app')->group(function (){
    // 公开接口:无需身份认证即可访问
    Route::post('login', [AuthController::class, 'login']);

    // 私有接口:需要 JWT Token 认证才能访问
    Route::middleware('auth:app')->group(function () {
        Route::post('logout', [AuthController::class, 'logout']);
        // 在此添加其他需要认证的 API 接口
    });
});

至此,CatchAdmin 专业版移动应用端开发框架的核心功能已介绍完毕。基于这套标准化的 API 开发架构,您可以快速构建安全、高效的移动应用后端服务。