JWT 实现基于API的用户认证
基于 JWT-Auth 实现 API 验证
如果想要了解其生成Token的算法原理,请自行查阅相关资料
需要提及的几点:
使用session存在的问题:
session和cookie是为了解决http无状态的方案。session是用户保存在服务器中的状态信息,cookie中则保存jsessionId,请求服务器时,服务器读取jsessionId从而确定用户的身份信息,而session+cookie用在restful接口上破坏了其“无状态”的特性,session运行时都是保存在内存中,而随着认证用户的增多,服务端的开销会明显增大。这也是restful最致力于通过“无状态”解决的问题。如果使用session,那么restful也就没有什么意义了
session降低了系统扩展性。用户认证之后,服务端做认证记录,如果认证的记录被保存在内存中的话,这意味着用户下次请求还必须要请求在这台服务器上,这样才能拿到授权的资源,这样在分布式的应用上,相应的限制了负载均衡器的能力。这也意味着限制了应用的扩展能力
cookie不安全,很容易导致跨站请求伪造攻击(CSRF)
token存在的问题:
如,如何确定token的过期时间?如果token的有效期过短,很容易造成用户用着用着就掉线的情况,降低用户体验。但目前看来好像并没有太好的办法,只能尽量延长token的有效期,或者每隔一次前端自动向服务端请求一次token
基于 JWT-Auth 的 token 验证体系
(亲测,希望这篇文章让大家少入坑)
运行软件版本
laravel 5.5
安装 JWT-Auth 扩展包
composer require tymon/jwt-auth "1.5.*"
安装完后在配置文件
config/app.php
中添加注册服务提供者和别名:...
'providers' => [
...
Tymon\JWTAuth\Providers\JWTAuthServiceProvider::class,
]
...
'aliases' => [
...
'JWTAuth' => Tymon\JWTAuth\Facades\JWTAuth::class,
]发布资源配置
php artisan vendor:publish --provider="Tymon\JWTAuth\Providers\JWTAuthServiceProvider"
运行以下命令生成密钥
key
在生成的config/jwt.php
中// 如果运行后报错,提示ERROR:Method Tymon\JWTAuth\Commands\JWTGenerateCommand::handle() does not exist,将vendor\tymon\jwt-auth\src\Commands\JWTGenerateCommand.php文件中的 fire() 方法修改为 handle()即可正常生成秘钥
php artisan jwt:generate编辑
app/Http/Kernel.php
添加jwt.auth
和jwt.refresh
到应用路由中间件数组:protected $routeMiddleware = [
...
'jwt.auth' => \Tymon\JWTAuth\Middleware\GetUserFromToken::class,
// 'jwt.refresh' => \Tymon\JWTAuth\Middleware\RefreshToken::class,
];JWTAuth
自身中间件\Tymon\JWTAuth\Middleware\GetUserFromToken
中包含了对生成token的各类情况的验证,以及异常的抛出。下面是其底层验证类GetUserFromToken::class
:// file_path : vendor\tymon\jwt-auth\src\Middleware\GetUserFromToken.php
<?php
/*
* This file is part of jwt-auth.
*
* (c) Sean Tymon <tymon148@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Tymon\JWTAuth\Middleware;
use Tymon\JWTAuth\Exceptions\JWTException; //验证异常类
use Tymon\JWTAuth\Exceptions\TokenExpiredException;//token过期异常验证类
class GetUserFromToken extends BaseMiddleware
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, \Closure $next)
{
if (! $token = $this->auth->setRequest($request)->getToken()) {
return $this->respond('tymon.jwt.absent', 'token_not_provided', 400);
}
try {
$user = $this->auth->authenticate($token);
} catch (TokenExpiredException $e) {
return $this->respond('tymon.jwt.expired', 'token_expired', $e->getStatusCode(), [$e]);
} catch (JWTException $e) {
return $this->respond('tymon.jwt.invalid', 'token_invalid', $e->getStatusCode(), [$e]);
}
if (! $user) {
return $this->respond('tymon.jwt.user_not_found', 'user_not_found', 404);
}
$this->events->fire('tymon.jwt.valid', $user);
return $next($request);
}
}其中,调用的
respond
的方法在vendor\tymon\jwt-auth\src\Middleware\BaseMiddleware.php
文件中/**
* Fire event and return the response.
*
* @param string $event
* @param string $error
* @param int $status
* @param array $payload
* @return mixed
*/
protected function respond($event, $error, $status, $payload = [])
{
$response = $this->events->fire($event, $payload, true);
return $response ?: $this->response->json(['error' => $error], $status);
}可看到,当出现异常需要返回错误信息时,会连带返回一个
fire event
的警告事件对象,这里不做详述。由底层代码中,可以了解到,我们如果想自定义自己所需要的验证方法,可以将这
GetUserFromToken::class
内容复制到我们自己自定义的中间件中。比如:创建自定义的验证中间件
App\Http\Middleware\JwtAuth.php
php artisan make:middleware JwtAuth
全部复制到自定义的中间件中后,校验下中间件中需要的类是否应用完全,命名空间是否正确等等,检查无误后根据需要自行定义需要的验证功能。
// demo
namespace App\Http\Middleware;
use Tymon\JWTAuth\Exceptions\JWTException;
use Tymon\JWTAuth\Exceptions\TokenExpiredException;
use Closure;
use Tymon\JWTAuth\Middleware\BaseMiddleware;
class JwtAuth extends BaseMiddleware
{
public function handle($request, \Closure $next)
{
if (! $token = $this->auth->setRequest($request)->getToken()) {
return $this->respond('tymon.jwt.absent', 'token_not_provided', 400);
}
try {
$user = $this->auth->authenticate($token);
} catch (TokenExpiredException $e) {
return $this->respond('tymon.jwt.expired', 'token_expired', $e->getStatusCode(), [$e]);
} catch (JWTException $e) {
return $this->respond('tymon.jwt.invalid', 'token_invalid', $e->getStatusCode(), [$e]);
}
if (! $user) {
return $this->respond('tymon.jwt.user_not_found', 'user_not_found', 404);
}
$this->events->fire('tymon.jwt.valid', $user);
return $next($request);
}
}定义完成后将自定义的中间件放入
app\Http\Kernel.php
的中间件数组中。protected $routeMiddleware = [
...
//'jwt.auth' => \Tymon\JWTAuth\Middleware\GetUserFromToken::class,
'jwt.auth_self' => \App\Http\Middleware\JwtAuth::class
];添加好后,即可在
routes/api.php
中对需要控制的api路由进行验证控制Route::group(['middleware'=>'jwt.auth_self'],function(){
// 需要控制的api路由
// ... code
});
我们现在可以对请求来的路由进行token的验证,那么接下来我们就需要生成这个token,让后续访问中间件中的请求路由都携带这个token就能实现验证。这里要提一下在安装
JWT-Auth
过程中生成的配置文件config/jwt.php
<?php
return [
...
/*
|--------------------------------------------------------------------------
| User Model namespace
|--------------------------------------------------------------------------
|
| Specify the full namespace to your User model.
| e.g. 'Acme\Entities\User'
|
*/
// 设置你的用户model,默认为laravel自带的 User model
'user' => 'App\User',
]如果需求需要,可在配置文件中修改用户
mode
,但配置的model
中需要引用Illuminate\Foundation\Auth\User as Authenticatable
,并继承,写法和User model
一致具体的请求登录以及获取token信息,登出等功能实现,可参考此文章
Laravel 5 中使用 JWT(Json Web Token) 实现基于API的用户认证,这里简单提及下常用到的有关其token的方法
<?php
namespace App\Http\Controller; use Tymon\JWTAuth\JWTAuth; class Auth{
public function test (JWTAuth $JWTAuth){ // 获取请求携带中的token
$token = $JWTAuth -> getToken();
// 获取token中的用户信息
$user = $JWTAuth -> parseToken() -> authenticate();
// 销毁此次生成的token
$JWTAuth->setToken( $JWTAuth->getToken() )->invalidate();
// 自定义生成token,如果需要
$JWTAuth->setToken('foo.bar.baz');
}
}
JWT 实现基于API的用户认证的更多相关文章
- Laravel 5 中使用 JWT(Json Web Token) 实现基于API的用户认证
在JavaScript前端技术大行其道的今天,我们通常只需在后台构建API提供给前端调用,并且后端仅仅设计为给前端移动App调用.用户认证是Web应用的重要组成部分,基于API的用户认证有两个最佳解决 ...
- 项目一:第十一天 2、运单waybill快速录入 3、权限demo演示-了解 5、权限模块数据模型 6、基于shiro实现用户认证-登录(重点)
1. easyui DataGrid行编辑功能 2. 运单waybill快速录入 3. 权限demo演示-了解 4. Apache shiro安全框架概述 5. 权限模块数据模型 6. 基于shiro ...
- Linux下基于LDAP统一用户认证的研究
Linux下基于LDAP统一用户认证的研究 本文出自 "李晨光原创技术博客" 博客,谢绝转载!
- 5分钟搞懂:基于token的用户认证
https://www.qikegu.com/easy-understanding/880 用户认证 用户认证或者说用户登录是确认某人确实是某人的过程,生活中靠身份证,网络上就要靠账号和密码.用户提供 ...
- 基于Ajax与用户认证系统的登录验证
一.登录页面 from django.contrib import admin from django.urls import path from blog import views urlpatte ...
- springSecurity + jwt + redis 前后端分离用户认证和授权
记录一下使用springSecurity搭建用户认证和授权的代码... 技术栈使用springSecurity + redis + JWT + mybatisPlus 部分代码来自:https://b ...
- 基于MongodbDB的用户认证-运维笔记
MongoDB默认是不认证的,默认没有账号,只要能连接上服务就可以对数据库进行各种操作,MongoDB认为安全最好的方法就是在一个可信的环境中运行它,保证之后可信的机器才能访问它,可能这些对一些要求高 ...
- tp5使用jwt生成token,做api的用户认证
首先 composer 安装 firebase/php-jwt github:https://github.com/firebase/php-jwt composer require firebas ...
- SpringSecurity学习之基于数据库的用户认证
SpringSecurity给我们提供了一套最基本的认证方式,可是这种方式远远不能满足大多数系统的需求.不过好在SpringSecurity给我们预留了许多可扩展的接口给我们,我们可以基于这些接口实现 ...
随机推荐
- python数据分析第二版:数据加载,存储和格式
一:读取数据的函数 1.读取csv文件 import numpy as np import pandas as pd data = pd.read_csv("C:\\Users\\Admin ...
- JavaWeb(七):EL表达式、自定义标签和JSTL
一.EL表达式 语法 el.jsp <%@page import="java.util.Date"%> <%@page import="com.atgu ...
- Codeforces 892E Envy
问题描述 小Q正在玩一个叠塔的游戏,游戏的目标是叠出尽可能高的塔.在游戏中,一共有n张矩形卡片,其中第i张卡片的 长度为a_i,宽度为b_i.小Q需要把所有卡片按一定顺序叠成一座塔,要求对于任意一个矩 ...
- UI自动化前置代码
一.前置代码: #导入包selenium from selenium import webdriverimport time#创键一个火狐对象driver=webdriver.Firefox()#防问 ...
- 将HTML转IMAGE
chrome --enable-logging --headless --disable-gpu --screenshot=d:\chrome.jpg --hide-scrollbars --wind ...
- 4412 使用usb摄像头拍照YUYV格式
一.内核设置 Linux内核中已经带有很完善的USB摄像头驱动,支持几乎所有的USB摄像头,我们只需要配置内核,选择上相应的Sensor型号即可. 配置内核,支持USB摄像头: Device Driv ...
- web大文件断点续传
1,项目调研 因为需要研究下断点上传的问题.找了很久终于找到一个比较好的项目. 在GoogleCode上面,代码弄下来超级不方便,还是配置hosts才好,把代码重新上传到了github上面. http ...
- 【テンプレート】LCA
LCA目前比较流行的算法主要有tarjian,倍增和树链剖分 1)tarjian 是一种离线算法,需要提前知道所有询问对 算法如下 1.读入所有询问对(u,v),并建好树(建议邻接表) 2.初始化每个 ...
- Xcode编辑器之filter查找功能和查看最近修改的文件
一,前言 有时候,我们的项目过大,创建类过多就会造成“目标文件”不好查找.这时候通过“filter”进行目录结构筛选无疑是最好的选择. 二,什么是filiter filiter 顾名思义为“过滤”,“ ...
- springmvc上传文件异常
症状: error:org.springframework.web.multipart.MultipartException: Current request is not a multipart r ...