在Lumen中使用jwt生成token和鉴权

孔安阳
2023-12-01

在Lumen中使用jwt生成token和鉴权

参考:https://blog.csdn.net/weixin_43303732/article/details/90443408

步骤:

  1. 添加依赖包:tymon/jwt-auth
  2. 生成密钥
  3. 启用jwt
  4. 修改Model
  5. 编写接口,生成token
  6. 配置鉴权
  7. 编写接口,测试用auth中间件鉴权

1) 添加依赖:

composer require tymon/jwt-auth

2)生成密钥

.env 文件下生成一个加密密钥

php artisan jwt:secret

3) 启用jwt

修改文件:bootstrap\app.php

$app->register(Tymon\JWTAuth\Providers\LumenServiceProvider::class); // 添加代码(启用jwt)

4)修改模型(Model)

<?php
namespace App\Models;

use Tymon\JWTAuth\Contracts\JWTSubject;

class User extends Model implements AuthenticatableContract, AuthorizableContract, JWTSubject
{
    use Authenticatable, Authorizable, HasFactory;

    ....略

	// 获取用户标识(即:用户的id,对应于生成的token的payload中的sub字段)
    public function getJWTIdentifier()
    {
        return $this->getKey();
    }
 
    // payload中附加的自定义数据
    public function getJWTCustomClaims()
    {
        return [
            'data'=>$this->data
        ];
    }
}

5)编写接口,生成token

新建文件:app\Http\Controllers\AuthController.php

<?php

namespace App\Http\Controllers;

use App\Models\User;
use Illuminate\Http\Request;

class AuthController
{
	// 为登录正确的用户生成token
    public function postLogin(Request $request)
    {
        $username = $request->json('username');
        $password = $request->json('password');
        
        // 数据库可以自已建一个表名叫users的表,要有name和password字段.
        $user = User::where('name', $username)->where('password', $password)->first();

		// payload中添加自定义数据
        $user->data = [
            'nickname'=>'测试',
            'username'=>$username,
            'url'=>'url'
        ];

        if ($user) {
            $token = Auth::login($user); // 生成token

            return [
                'status'=>200,
                'data'=>[
                    'token'=>$token
                ]
            ];
        }else{
            return [
                'status'=>500,
                'message'=>'帐号不存在'
            ];
        }
    }
}

添加路由:routes\web.php

$router->post('/api/auth/login', '\App\Http\Controllers\AuthController@postLogin');

测试:

POST http://xxxx/api/auth/login
Content-Type:application/json
{
  "username":"test",
  "password":"123456"
}

返回:(https://tool.box3.cn/jwt.html 可以查看token解析出的结果,payload中的[sub]即数据库用户的id)

{
"status": 200,
"data":{
"token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOlwvXC92Y2hhdGJvdC5sb2NcL2FwaVwvYXV0aFwvbG9naW4iLCJpYXQiOjE2MzEwODYyMTcsImV4cCI6MTYzMTA4OTgxNywibmJmIjoxNjMxMDg2MjE3LCJqdGkiOiJ4RXdEeThGcE5KM09NdUdoIiwic3ViIjoxLCJwcnYiOiIyM2JkNWM4OTQ5ZjYwMGFkYjM5ZTcwMWM0MDA4NzJkYjdhNTk3NmY3IiwiZGF0YSI6eyJuaWNrbmFtZSI6Ilx1NmQ0Ylx1OGJkNSIsInVzZXJuYW1lIjoidGVzdCIsInVybCI6InVybCJ9fQ.GmFd5AgT2FOzkW3O_c10dUPdRLj7FDLiu_HHZxqR0f4"
}
}

6)配置鉴权

检查文件是否存在:config\auth.php

如果不存在可以把:vendor\laravel\lumen-framework\config\auth.php复制过来。

修改文件:config\auth.php

'guards' => [
    'api' => [
        		'driver' => 'jwt', // 使用jwt
                'provider' => 'users' // 使用providers中的users节的配置
             ], 
],

'providers' => [
        'users' => [
            'driver' => 'eloquent', // 使用数据库模型(鉴权方法依赖数据库)
            'model' => \App\Models\User::class, // 具体的模型(生成token时的用户来源)
        ],
    ],

修改文件:bootstrap\app.php

$app->configure('auth'); // 添加代码
$app->routeMiddleware([
    'auth' => App\Http\Middleware\Authenticate::class, // 打开注释
]);
$app->register(App\Providers\AuthServiceProvider::class); // 打开注释

7)编写接口,测试用auth中间件鉴权

控制器中添加方法:app\Http\Controllers\AuthController.php

    public function test(Request $request)
    {
        var_dump(Auth::user()->id);
    }

配置路由:

$router->group([
    'prefix'=>'api/jwt', 
    'middleware'=>'auth' // 使用在bootstrap\app.ph中打开的中间件鉴权
], function() use ($router){
    $router->get('test', '\App\Http\Controllers\AuthController@test');
});

测试:

GET http://xxxx/api/jwt/test
Authorization:Bearer 这里填token(Bearer+空格+token)

返回:

int(1)

如token无效返回:

Unauthorized.

注:

jwt的配置参数可以查看:vendor\tymon\jwt-auth\config\config.php

可以使用vendor\tymon\jwt-auth\src\Http\Middleware\Authenticate.php代替默认的鉴权中间件。

JWT – PHP生成token,JAVA解析token

php
参考:http://www.koukousky.com/back/2483.html

composer require lcobucci/jwt “^3.4”

<?php /** * jwt封装的一个简单的类 */ use Lcobucci\JWT\Configuration; use Lcobucci\JWT\Signer\Hmac\Sha256; use Lcobucci\JWT\Signer\Key\InMemory; use DateTimeImmutable; use Lcobucci\JWT\Token\Plain; use Lcobucci\JWT\Validation\RequiredConstraintsViolated; use Lcobucci\JWT\Validation\Constraint\SignedWith; class Service { /** * 配置秘钥加密 * @return Configuration */ public static function getConfig() { $configuration = Configuration::forSymmetricSigner( // You may use any HMAC variations (256, 384, and 512) new Sha256(), // replace the value below with a key of your own! InMemory::base64Encoded('YWFhc0pOU0RLSkJITktKU0RiamhrMTJiM2Joa2ox') // You may also override the JOSE encoder/decoder if needed by providing extra arguments here ); return $configuration; } /** * 签发令牌 */ public static function createToken() { $config = self::getConfig(); assert($config instanceof Configuration); $now = new DateTimeImmutable(); // 时间必须用这个类,否则报错 $token = $config->builder() // 签发人 ->issuedBy('http://example.com') // 受众 ->permittedFor('http://example.org') // JWT ID 编号 唯一标识 ->identifiedBy('123') // 签发时间 ->issuedAt($now) // 在1分钟后才可使用 ->canOnlyBeUsedAfter($now->modify('+1 minute')) // 过期时间1小时 ->expiresAt($now->modify('+1 hour')) // 自定义uid 额外参数 ->withClaim('uid', 1) // 自定义header 参数 ->withHeader('foo', 'bar') // 生成token ->getToken($config->signer(), $config->signingKey()); //result: //eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiIsImZvbyI6ImJhciJ9.eyJpc3MiOiJodHRwOlwvXC9leGFtcGxlLmNvbSIsImF1ZCI6Imh0dHA6XC9cL2V4YW1wbGUub3JnIiwianRpIjoiNGYxZzIzYTEyYWEiLCJpYXQiOjE2MDk0Mjk3MjMsIm5iZiI6MTYwOTQyOTc4MywiZXhwIjoxNjA5NDMzMzIzLCJ1aWQiOjF9.o4uLWzZjk-GJgrxgirypHhXKkMMUEeL7z7rmvmW9Mnw //base64 decode: //{"typ":"JWT","alg":"HS256","foo":"bar"}{"iss":"http:\/\/example.com","aud":"http:\/\/example.org","jti":"4f1g23a12aa","iat":1609429723,"nbf":1609429783,"exp":1609433323,"uid":1}[6cb`"*Gr0ńxoL return $token->toString(); } /** * 解析令牌 */ public static function parseToken(string $token) { $config = self::getConfig(); assert($config instanceof Configuration); $token = $config->parser()->parse('eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiIsImZvbyI6ImJhciJ9.eyJpc3MiOiJodHRwOlwvXC9leGFtcGxlLmNvbSIsImF1ZCI6Imh0dHA6XC9cL2V4YW1wbGUub3JnIiwianRpIjoiNGYxZzIzYTEyYWEiLCJpYXQiOjE2MDk0Mjk3MjMsIm5iZiI6MTYwOTQyOTc4MywiZXhwIjoxNjA5NDMzMzIzLCJ1aWQiOjF9.o4uLWzZjk-GJgrxgirypHhXKkMMUEeL7z7rmvmW9Mnw' ); assert($token instanceof Plain); dump($token->headers()); // Retrieves the token headers dump($token->claims()); // Retrieves the token claims } /** * 验证令牌 */ public static function validationToken(string $token) { $config = self::getConfig(); assert($config instanceof Configuration); $token = $config->parser()->parse($token); assert($token instanceof Plain); //Lcobucci\JWT\Validation\Constraint\IdentifiedBy: 验证jwt id是否匹配 //Lcobucci\JWT\Validation\Constraint\IssuedBy: 验证签发人参数是否匹配 //Lcobucci\JWT\Validation\Constraint\PermittedFor: 验证受众人参数是否匹配 //Lcobucci\JWT\Validation\Constraint\RelatedTo: 验证自定义cliam参数是否匹配 //Lcobucci\JWT\Validation\Constraint\SignedWith: 验证令牌是否已使用预期的签名者和密钥签名 //Lcobucci\JWT\Validation\Constraint\ValidAt: 验证要求iat,nbf和exp(支持余地配置) //验证jwt id是否匹配 $validate_jwt_id = new \Lcobucci\JWT\Validation\Constraint\IdentifiedBy('123'); $config->setValidationConstraints($validate_jwt_id); //验证签发人url是否正确 $validate_issued = new \Lcobucci\JWT\Validation\Constraint\IssuedBy('http://example.com'); $config->setValidationConstraints($validate_issued); //验证客户端url是否匹配 $validate_aud = new \Lcobucci\JWT\Validation\Constraint\PermittedFor('http://example.org'); $config->setValidationConstraints($validate_aud); //验证是否过期 $timezone = new \DateTimeZone('Asia/Shanghai'); $now = new \Lcobucci\Clock\SystemClock($timezone); $validate_jwt_at = new \Lcobucci\JWT\Validation\Constraint\ValidAt($now); $config->setValidationConstraints($validate_jwt_at); $constraints = $config->validationConstraints(); try { $config->validator()->assert($token, ...$constraints); } catch (RequiredConstraintsViolated $e) { // list of constraints violation exceptions: var_dump($e->violations()); } } } JAVA com.auth0 java-jwt 3.18.2 import com.auth0.jwt.JWT; import com.auth0.jwt.JWTVerifier; import com.auth0.jwt.algorithms.Algorithm; import com.auth0.jwt.exceptions.JWTDecodeException; import com.auth0.jwt.interfaces.DecodedJWT; public String getAccount(){ // 不校验key,直接解析 DecodedJWT jwt = JWT.decode(account); // 校验key后解析 // String publicKey = ""; // Algorithm algorithm = Algorithm.HMAC256(publicKey); // publicKey需要与生成方的一致 // JWTVerifier verifier = JWT.require(algorithm).build(); // DecodedJWT jwt = verifier.verify(account); return jwt.getClaim("account").asString(); }
 类似资料: