欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

laravel 商城实战开发 Dingoapi 用户管理

程序员文章站 2022-03-03 21:45:58
...

Dingoapi

模型注入

app/Http/Kernel.php

  1. protected $routeMiddleware = [
  2. ......
  3. 'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
  4. ];

去除data

https://packagist.org/packages/liyu/dingo-serializer-switch

  1. $api->version('v1',
  2. ['middleware' => 'serializer:array'],
  3. function ($api) {
  4. });

Laravel API 认证:JWT 认证

  • 为什么要用JWT
  • JWT 是什么

文档

什么是 jwt ?

JWT 全称叫 JSON Web Token, 是一个非常轻巧的规范。这个规范允许我们使用 JWT 在用户和服务器之间传递安全可靠的信息。

安装 jwt-auth

  1. composer require tymon/jwt-auth:1.0.x-dev

发布配置

运行以下命令以发布包配置文件:

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

您现在应该有一个config/jwt.php文件,允许您配置此包的基础知识。

生成密钥

我已经包含了一个帮助命令来为你生成一个密钥:

  1. php artisan jwt:secret

更新您的用户模型

首先,您需要Tymon\JWTAuth\Contracts\JWTSubject在 User 模型上实现合同,这需要您实现 2 个方法getJWTIdentifier()getJWTCustomClaims().

下面的示例应该让您了解它的外观。显然,您应该根据自己的需要进行任何更改。

  1. <?php
  2. namespace App;
  3. use Tymon\JWTAuth\Contracts\JWTSubject;
  4. use Illuminate\Notifications\Notifiable;
  5. use Illuminate\Foundation\Auth\User as Authenticatable;
  6. class User extends Authenticatable implements JWTSubject
  7. {
  8. use Notifiable;
  9. // Rest omitted for brevity
  10. /**
  11. * Get the identifier that will be stored in the subject claim of the JWT.
  12. *
  13. * @return mixed
  14. */
  15. public function getJWTIdentifier()
  16. {
  17. return $this->getKey();
  18. }
  19. /**
  20. * Return a key value array, containing any custom claims to be added to the JWT.
  21. *
  22. * @return array
  23. */
  24. public function getJWTCustomClaims()
  25. {
  26. return [];
  27. }
  28. }

配置身份验证保护

在该config/auth.php文件中,您需要进行一些更改以配置 Laravel 以使用jwt防护来支持您的应用程序身份验证。

对文件进行以下更改:

  1. 'defaults' => [
  2. 'guard' => 'api',
  3. 'passwords' => 'users',
  4. ],
  5. ...
  6. 'guards' => [
  7. 'api' => [
  8. 'driver' => 'jwt',
  9. 'provider' => 'users',
  10. ],
  11. ],

这里我们告诉api守卫使用jwt驱动程序,我们将api守卫设置为默认值。

我们现在可以使用 Laravel 内置的 Auth 系统,由 jwt-auth 在幕后完成工作!

因为我们用的dingoapi 我们还需要在 config/api.php 里面修改:

  1. 'auth' => [
  2. 'jwt' => 'Dingo\Api\Auth\Provider\JWT',
  3. ],

创建路由文件

  1. <?php
  2. use App\Http\Controllers\Api\UserController;
  3. use App\Http\Controllers\Auth\LoginController;
  4. use App\Http\Controllers\Auth\RegisterController;
  5. $api = app('Dingo\Api\Routing\Router');
  6. $api->version(['v1','v2'], ['middleware' => 'api.throttle', 'limit' => 100, 'expires' => 5],function ($api) {
  7. $api->group(['prefix' => 'auth'], function ($api) {
  8. // 注册
  9. $api->post('register', [RegisterController::class, 'store']);
  10. $api->post('login', [LoginController::class, 'login']);
  11. });
  12. });

创建控制器

  1. php artisan make:controller Auth/LoginController
  2. php artisan make:controller Auth/RegisterController

RegisterController

  1. /**
  2. * 用户注册
  3. */
  4. public function store(RegisterRequest $request)
  5. {
  6. $user = new User();
  7. $user->name = $request->input('name');
  8. $user->email = $request->input('email');
  9. $user->password = bcrypt($request->input('password'));
  10. if ($request->input('openid')) $user->openid = $request->input('openid');
  11. if ($request->input('avatar')) $user->avatar = $request->input('avatar');
  12. $user->save();
  13. return $this->response->created();
  14. }

RegisterRequest

创建数据注册数据验证

  1. php artisan make:request Auth/RegisterRequest
  1. /**
  2. * Get the validation rules that apply to the request.
  3. *
  4. * @return array
  5. */
  6. public function rules()
  7. {
  8. return [
  9. 'name' => 'required|max:16',
  10. 'email' => 'required|email|unique:users',
  11. 'password' => 'required|min:6|max:16|confirmed',
  12. 'openid' => 'sometimes|required|unique:users,openid'
  13. ];
  14. }
  15. public function messages()
  16. {
  17. return [
  18. 'name.required' => '昵称 不能为空',
  19. 'name.max' => '昵称 不能超过16个字符',
  20. 'openid.required' => 'openid 不能为空',
  21. 'openid.unique' => 'openid 已绑定其他用户',
  22. ];
  23. }

完成登录

LoginController

文档

因为我们用户有禁用的功能 所以我们还需要调整一下

  1. /**
  2. * Get a JWT via given credentials.
  3. *
  4. * @return \Illuminate\Http\JsonResponse
  5. */
  6. public function login()
  7. {
  8. $credentials = request(['email', 'password']);
  9. if (! $token = auth()->attempt($credentials)) {
  10. return response()->json(['error' => 'Unauthorized'], 401);
  11. }
  12. return $this->respondWithToken($token);
  13. }
  14. /**
  15. * Get the authenticated User.
  16. *
  17. * @return \Illuminate\Http\JsonResponse
  18. */
  19. public function me()
  20. {
  21. return response()->json(auth()->user());
  22. }
  23. /**
  24. * Log the user out (Invalidate the token).
  25. *
  26. * @return \Illuminate\Http\JsonResponse
  27. */
  28. public function logout()
  29. {
  30. auth()->logout();
  31. return response()->json(['message' => 'Successfully logged out']);
  32. }
  33. /**
  34. * Refresh a token.
  35. *
  36. * @return \Illuminate\Http\JsonResponse
  37. */
  38. public function refresh()
  39. {
  40. return $this->respondWithToken(auth()->refresh());
  41. }
  42. /**
  43. * Get the token array structure.
  44. *
  45. * @param string $token
  46. *
  47. * @return \Illuminate\Http\JsonResponse
  48. */
  49. protected function respondWithToken($token)
  50. {
  51. return response()->json([
  52. 'access_token' => $token,
  53. 'token_type' => 'bearer',
  54. 'expires_in' => auth()->factory()->getTTL() * 60
  55. ]);
  56. }
  1. /**
  2. * 登录
  3. */
  4. public function login(LoginRequest $request)
  5. {
  6. $credentials = request(['email', 'password']);
  7. if (!$token = auth('api')->attempt($credentials)) {
  8. return $this->response->errorUnauthorized();
  9. }
  10. // 检查用户状态
  11. $user = auth('api')->user();
  12. if ($user->is_locked == 1) {
  13. return $this->response->errorForbidden('被锁定');
  14. }
  15. return $this->respondWithToken($token);
  16. }

LoginRequest

  1. php artisan make:request Auth/LoginRequest
  1. /**
  2. * Get the validation rules that apply to the request.
  3. *
  4. * @return array
  5. */
  6. public function rules()
  7. {
  8. return [
  9. 'email' => 'required|email',
  10. 'password' => 'required|min:6|max:16',
  11. ];
  12. }

退出登录

路由

  1. $api->group(['middleware' => 'api.auth'], function ($api) {
  2. $api->post('logout', [LoginController::class, 'logout']);
  3. });
  1. /**
  2. * 退出登录
  3. */
  4. public function logout()
  5. {
  6. auth('api')->logout();
  7. return $this->response->noContent();
  8. }

刷新TOKEN

  1. // 刷新token
  2. $api->post('refresh', [LoginController::class, 'refresh']);
  1. /**
  2. * 刷新token
  3. */
  4. public function refresh()
  5. {
  6. return $this->respondWithToken(auth('api')->refresh());
  7. }

辅助函数

自定义全局辅助函数

app 目录下新建 helpers.php 文件, 并修改 composer.json, 加入到自动加载中:

  1. "autoload": {
  2. "psr-4": {
  3. "App\\": "app/",
  4. "Database\\Factories\\": "database/factories/",
  5. "Database\\Seeders\\": "database/seeders/"
  6. },
  7. "files": [
  8. "app/helpers.php"
  9. ]
  10. },

刷新自动加载:

  1. $ composer dump-autoload

后台用户列表

创建后台控制器

  1. php artisan make:controller Admin/UserController --api

路由

  1. $api->group(['prefix' => 'admin'], function ($api){
  2. // 当前登录用户详情
  3. $api->get('user', [\App\Http\Controllers\Admin\UserController::class, 'userInfo'])->name('user.info');
  4. // 禁用用户/启用用户
  5. $api->patch('users/{user}/lock', [\App\Http\Controllers\Admin\UserController::class, 'lock'])->name('users.lock');
  6. // 用户管理资源路由
  7. $api->resource('users', \App\Http\Controllers\Admin\UserController::class, [
  8. 'only' => ['index', 'show', 'store', 'update']
  9. ]);
  10. });
  1. <?php
  2. namespace App\Http\Controllers\Admin;
  3. use App\Http\Controllers\BaseController;
  4. use App\Models\User;
  5. use App\Transformers\UserTransformer;
  6. use Illuminate\Http\Request;
  7. class UserController extends BaseController
  8. {
  9. /**
  10. * 用户个人信息详情
  11. */
  12. public function userInfo()
  13. {
  14. return $this->response->item(auth('api')->user(), new UserTransformer());
  15. }
  16. /**
  17. * 用户列表
  18. */
  19. public function index(Request $request)
  20. {
  21. $name = $request->input('name');
  22. $email = $request->input('email');
  23. $phone = $request->input('phone');
  24. $users = User::when($name, function ($query) use ($name) {
  25. $query->where('name', 'like', "%$name%");
  26. })
  27. ->when($email, function ($query) use ($email) {
  28. $query->where('email', $email);
  29. })
  30. ->when($phone, function ($query) use ($phone) {
  31. $query->where('phone', $phone);
  32. })
  33. ->orderBy('updated_at', 'desc')
  34. ->paginate($request->query('pageSize', 10), ['*'], 'current');
  35. return $this->response->paginator($users, new UserTransformer());
  36. }
  37. /**
  38. * 添加用户
  39. */
  40. public function store(Request $request)
  41. {
  42. $request->validate([
  43. 'name' => 'required|max:16',
  44. 'email' => 'required|email|unique:users',
  45. 'password' => 'required|min:6',
  46. ]);
  47. User::create($request->all());
  48. return $this->response->created();
  49. }
  50. /**
  51. * 更新用户
  52. */
  53. public function update(Request $request, User $user)
  54. {
  55. $request->validate([
  56. 'name' => 'required|max:16',
  57. 'email' => 'required|email',
  58. ]);
  59. if ($user->id == 1 || $user->id == 2) return $this->response->errorBadRequest('禁止操作系统数据');
  60. $user->update($request->all());
  61. return $this->response->noContent();
  62. }
  63. /**
  64. * 用户详情
  65. */
  66. public function show(User $user)
  67. {
  68. return $this->response->item($user, new UserTransformer());
  69. }
  70. /**
  71. * 禁用和启用用户
  72. */
  73. public function lock(User $user)
  74. {
  75. if ($user->id == 1 || $user->id == 2) return $this->response->errorBadRequest('禁止操作系统数据');
  76. $user->is_locked = $user->is_locked == 0 ? 1 : 0;
  77. $user->save();
  78. return $this->response->noContent();
  79. }
  80. }

Transformers

  1. <?php
  2. namespace App\Transformers;
  3. use App\Models\User;
  4. use League\Fractal\TransformerAbstract;
  5. class UserTransformer extends TransformerAbstract
  6. {
  7. public function transform(User $user)
  8. {
  9. return [
  10. 'id' => $user->id,
  11. 'name' => $user->name,
  12. 'email' => $user->email,
  13. 'phone' => $user->phohe,
  14. 'avatar' => $user->avatar,
  15. 'openid' => $user->openid,
  16. ];
  17. }
  18. }

分类管理

  1. /**
  2. * 分类管理
  3. */
  4. // 分类禁用和启用
  5. $api->patch('category/{category}/status', [\App\Http\Controllers\Admin\CategoryController::class, 'status'])->name('category.status');
  6. // 分类管理资源路由
  7. $api->resource('category', \App\Http\Controllers\Admin\CategoryController::class, [
  8. 'except' => ['destroy']
  9. ]);

控制器

  1. <?php
  2. namespace App\Http\Controllers\Admin;
  3. use App\Http\Controllers\BaseController;
  4. use App\Models\Category;
  5. use Illuminate\Http\Request;
  6. class CategoryController extends BaseController
  7. {
  8. /**
  9. * 分类列表
  10. */
  11. public function index(Request $request)
  12. {
  13. $type = $request->input('type');
  14. if ($type == 'all') {
  15. return cache_category_all();
  16. } else {
  17. return cache_category();
  18. }
  19. }
  20. /**
  21. * 添加分类 最大2级分类
  22. */
  23. public function store(Request $request)
  24. {
  25. $insertData = $this->checkInput($request);
  26. if (!is_array($insertData)) return $insertData;
  27. Category::create($insertData);
  28. return $this->response->created();
  29. }
  30. /**
  31. * 分类详情
  32. */
  33. public function show(Category $category)
  34. {
  35. return $category;
  36. }
  37. /**
  38. * 更新分类
  39. */
  40. public function update(Request $request, Category $category)
  41. {
  42. if ($category->id < 42) return $this->response->errorBadRequest('系统数据禁止编辑, 请自行创建数据');
  43. $updateData = $this->checkInput($request);
  44. if (!is_array($updateData)) return $updateData;
  45. $category->update($updateData);
  46. return $this->response->noContent();
  47. }
  48. /**
  49. * 验证提交的参数
  50. */
  51. protected function checkInput($request)
  52. {
  53. // 验证参数
  54. $request->validate([
  55. 'name' => 'required|max:16'
  56. ], [
  57. 'name.required' => '分类名称 不能为空'
  58. ]);
  59. // 获取分组
  60. $group = $request->input('group', 'goods');
  61. // 获取pid
  62. $pid = $request->input('pid', 0);
  63. // 计算level
  64. $level = $pid == 0 ? 1 : (Category::find($pid)->level + 1);
  65. // 不能超过3级分类
  66. if ($level > 2) {
  67. return $this->response->errorBadRequest('不能超过二级分类');
  68. }
  69. return [
  70. 'name' => $request->input('name'),
  71. 'pid' => $pid,
  72. 'level' => $level,
  73. 'group' => $group
  74. ];
  75. }
  76. /**
  77. * 状态禁用和启用
  78. */
  79. public function status(Category $category)
  80. {
  81. if ($category->id < 42) return $this->response->errorBadRequest('系统数据禁止编辑, 请自行创建数据');
  82. $category->status = $category->status == 1 ? 0 : 1;
  83. $category->save();
  84. return $this->response->noContent();
  85. }
  86. }

Helpers.php

  1. /**
  2. * 缓存没被禁用的分类
  3. */
  4. if (!function_exists('cache_category')) {
  5. function cache_category ()
  6. {
  7. return cache()->rememberForever('cache_category', function () {
  8. return categoryTree('goods', 1);
  9. });
  10. }
  11. }
  12. /**
  13. * 缓存所有的分类
  14. */
  15. if (!function_exists('cache_category_all')) {
  16. function cache_category_all ()
  17. {
  18. return cache()->rememberForever('cache_category_all', function () {
  19. return categoryTree('goods');
  20. });
  21. }
  22. }
  1. /**
  2. * 清空分类缓存
  3. */
  4. if (!function_exists('forget_cache_category')) {
  5. function forget_cache_category ()
  6. {
  7. cache()->forget('cache_category');
  8. cache()->forget('cache_category_all');
  9. cache()->forget('cache_category_menu');
  10. cache()->forget('cache_category_menu_all');
  11. }
  12. }
  1. class CategoryTransformer extends TransformerAbstract
  2. {
  3. public function transform(Category $category)
  4. {
  5. return [
  6. 'id' => $category->id,
  7. 'pid' => $category->pid,
  8. 'name' => $category->name,
  9. ];
  10. }
  11. }