When the same laravel project has multiple terminals (mobile terminal, management terminal...) and all need to use jwt for user verification , if there are multiple user tables (usually there are), token isolation needs to be done, otherwise there will be a problem that the token on the mobile side can also request the management side, causing the user to exceed his authority.
The reason why this problem occurs is that laravel's jwt token only stores the value of the primary key of the data table by default, and does not distinguish which table it is. So as long as the ID carried in the token exists in your user table, it will lead to unauthorized verification.
Let’s take a look at the original appearance of laravel’s jwt token:
{ "iss": "http://your-request-url", "iat": 1558668215, "exp": 1645068215, "nbf": 1558668215, "jti": "XakIDuG7K0jeWGDi", "sub": 1, "prv": "92d5e8eb1b38ccd11476896c19b0e44512b2aacd" }
The sub field that carries data is the sub field, and the other fields are the verification fields of jwt.
We only see that the value of sub is 1, and it does not indicate which table or validator it belongs to. When this token passes your verification middleware, you can use different guards to get the user with the corresponding table ID 1 (please check the laravel documentation to learn about guard).
To solve the problem of user overreaching, we only need to bring our custom fields on the token to distinguish which table or validator generated it, and then Write your own middleware to verify that our custom fields match our expectations.
We know that to use jwt verification, the user model must implement the JWTSubject interface (the code is taken from the jwt document):
<?php namespace App; use Tymon\JWTAuth\Contracts\JWTSubject; use Illuminate\Notifications\Notifiable; use Illuminate\Foundation\Auth\User as Authenticatable; class User extends Authenticatable implements JWTSubject { use Notifiable; // Rest omitted for brevity /** * Get the identifier that will be stored in the subject claim of the JWT. * * @return mixed */ public function getJWTIdentifier() { return $this->getKey(); } /** * Return a key value array, containing any custom claims to be added to the JWT. * * @return array */ public function getJWTCustomClaims() { return []; } }
We can Take a look at the functions of these two implemented methods:
Next we can add our custom information to the user model that implements the getJWTCustomClaims method.
Administrator model:
/** * 额外在 JWT 载荷中增加的自定义内容 * * @return array */ public function getJWTCustomClaims() { return ['role' => 'admin']; }
Mobile user model:
/** * 额外在 JWT 载荷中增加的自定义内容 * * @return array */ public function getJWTCustomClaims() { return ['role' => 'user']; }
A role name is added here as the user ID.
The token generated by the administrator will look like this:
{ "iss": "http://your-request-url", "iat": 1558668215, "exp": 1645068215, "nbf": 1558668215, "jti": "XakIDuG7K0jeWGDi", "sub": 1, "prv": "92d5e8eb1b38ccd11476896c19b0e44512b2aacd", "role": "admin" }
The token generated by the mobile user will look like this:
{ "iss": "http://your-request-url", "iat": 1558668215, "exp": 1645068215, "nbf": 1558668215, "jti": "XakIDuG7K0jeWGDi", "sub": 1, "prv": "92d5e8eb1b38ccd11476896c19b0e44512b2aacd", "role": "user" }
We can see that there is one more of ourselves here The added role field corresponds to our user model.
Next, we will write a middleware ourselves. After parsing the token, we will determine whether it is the role we want. If it matches, it will pass. If it does not match, it will report 401.
Here is a globally usable middleware (recommended to be used before user verification middleware):
<?php /** * Created by PhpStorm. * User: wlalala * Date: 2019-04-17 * Time: 13:55 */ namespace App\Http\Middleware; use Closure; use Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException; use Tymon\JWTAuth\Exceptions\JWTException; use Tymon\JWTAuth\Http\Middleware\BaseMiddleware; class JWTRoleAuth extends BaseMiddleware { /** * Handle an incoming request. * * @param $request * @param Closure $next * @param null $role * @return mixed */ public function handle($request, Closure $next, $role = null) { try { // 解析token角色 $token_role = $this->auth->parseToken()->getClaim('role'); } catch (JWTException $e) { /** * token解析失败,说明请求中没有可用的token。 * 为了可以全局使用(不需要token的请求也可通过),这里让请求继续。 * 因为这个中间件的责职只是校验token里的角色。 */ return $next($request); } // 判断token角色。 if ($token_role != $role) { throw new UnauthorizedHttpException('jwt-auth', 'User role error'); } return $next($request); } }
Register the middleware in app/Http/Kernel.php:
/** * The application's route middleware. * * These middleware may be assigned to groups or used individually. * * @var array */ protected $routeMiddleware = [ // ...省略 ... // 多表jwt验证校验 'jwt.role' => \App\Http\Middleware\JWTRoleAuth::class, ];
Next, add the route that requires user verification Add our middleware to the group:
Route::group([ 'middleware' => ['jwt.role:admin', 'jwt.auth'], ], function ($router) { // 管理员验证路由 // ... }); Route::group([ 'middleware' => ['jwt.role:user', 'jwt.auth'], ], function ($router) { // 移动端用户验证路由 // ... });
This completes jwt multi-table user verification isolation.
For more Laravel related technical articles, please visit the Laravel Tutorial column to learn!
The above is the detailed content of Laravel jwt multi-table validation isolation. For more information, please follow other related articles on the PHP Chinese website!