很多站长朋友们都不太清楚php如何认证jwt,今天小编就来给大家整理php如何认证jwt,希望对各位有所帮助,具体内容如下:
本文目录一览: 1、 Thinkphp5.1 使用jwt生成和解析token 一 2021-04-01 2、 程序员应该如何设计更优雅的Token认证方式? 3、 PHP---APP接口02 4、 JWT如何实现登录、鉴权 5、 JWT 认证过程 6、 SpringSecurity+JWT认证流程解析 Thinkphp5.1 使用jwt生成和解析token 一 2021-04-01一 通过Composer安装firebase/php-jwt 5.2.1版本
二 common.php公共函数文件
程序员应该如何设计更优雅的Token认证方式?通过上一篇你大体已经了解session和cookie认证了,session认证需要服务端做大量的工作来保证session信息的一致性以及session的存储,所以现代的web应用在认证的解决方案上更倾向于客户端方向,cookie认证是基于客户端方式的,但是cookie缺点也很明显,到底有哪些缺点可以跳转上一次的文章。那有没有一种比较折中的方案呢?有的
把认证信息保存在客户端,关键点就是安全的验证,如果能解决认证信息的安全性问题,完全可以把认证信息保存在客户端,服务端完全无认证状态,这样的话服务端扩展起来要方便很多。关于信息的安全解决方案,现在普遍的做法就是签名机制,像微信公众接口的验证方式就基于签名机制。
当用户成功登陆系统并成功验证有效之后,服务器会利用某种机制产生一个token字符串,这个token中可以包含很多信息,例如来源IP,过期时间,用户信息等, 把这个字符串下发给客户端,客户端在之后的每次请求中都携带着这个token,携带方式其实很自由,无论是cookie方式还是其他方式都可以,但是必须和服务端协商一致才可以。当然这里我不推荐cookie。当服务端收到请求,取出token进行验证(可以验证来源ip,过期时间等信息),如果合法则允许进行操作。
基于token的验证方式也是现代互联网普通使用的认证方式,那它有什么优点吗?
1. 支持跨域访问,Cookie是不允许垮域访问的,这一点对Token机制是不存在的,前提是传输的用户认证信息通过HTTP头传输.
2. 无状态:Token机制在服务端不需要存储session信息,因为Token自身包含了所有登录用户的信息,只需要在客户端的cookie或本地介质存储状态信息.
3. 解耦 不需要绑定到一个特定的身份验证方案。Token可以在任何地方生成,只要在你的API被调用的时候,你可以进行Token生成调用即可.
4. 适用性更广:只要是支持http协议的客户端,就可以使用token认证。
5. 服务端只需要验证token的安全,不必再去获取登录用户信息,因为用户的登录信息已经在token信息中。
6. 基于标准化:你的API可以采用标准化的 JSON Web Token (JWT). 这个标准已经存在多个后端库(.NET, Ruby, Java,Python,PHP)和多家公司的支持(如:Firebase,Google, Microsoft).
那基于token的认证方式有哪些缺点呢?
1. 网络传输的数据量增大:由于token中存储了大量的用户和安全相关的信息,所以比单纯的cookie信息要大很多,传输过程中需要消耗更多流量,占用更多带宽,
2. 和所有的客户端认证方式一样,如果想要在服务端控制token的注销有难度,而且也很难解决客户端的劫持问题。
3. 由于token信息在服务端增加了一次验证数据完整性的操作,所以比session的认证方式增加了cpu的开销。
但是整体来看,基于token的认证方式还是比session和cookie方式要有很大优势。在所知的token认证中,jwt是一种优秀的解决方案
一个JWT实际上就是一个字符串,它由三部分组成,头部、载荷与签名。
header典型的由两部分组成:token的类型(“JWT”)和算法名称(比如:HMAC SHA256或者RSA等等)。
Payload 部分也是一个JSON对象,用来存放实际需要传递的数据。JWT 规定了7个官方字段,供选用。
除了以上字段之外,你完全可以添加自己想要的任何字段,这里还是提醒一下,由于jwt的标准,信息是不加密的,所以一些敏感信息最好不要添加到json里面
为了得到签名部分,你必须有编码过的header、编码过的payload、一个秘钥(这个秘钥只有服务端知道),签名算法是header中指定的那个,然对它们签名即可。
算出签名以后,把 Header、Payload、Signature 三个部分拼成一个字符串,每个部分之间用"点"(.)分隔,就可以返回给用户。需要提醒一下:base64是一种编码方式,并非加密方式。
基于token的认证方式,大体流程为:
这里再重复一次,无论是token认证,cookie认证,还是session认证,一旦别人拿到客户端的标识,还是可以伪造操作。所以采用任何一种认证方式的时候请考虑加入来源ip或者白名单,过期时间,另外有条件的情况下一定要使用https。
PHP---APP接口02JSONXML
XML: 是一种标记语言,设计的宗旨是传输数据
JSON: 轻量级的数据交换格式
APP接口主要是用JSON输出格式
APP接口输出格式三要素:
1. code::错误码
2. msg:错误码对应的描述
3. data:接口返回的数据
谁有权限调用APP接口,客户端需要带着凭证来调用APP接口
JWT的原理:
服务端认证之后,生成一个JSON对象,返回给用户。后续客户端所有请求都会带上这个JSON对象。服务端依靠这个JSON对象来认定用户身份。
组成: Header, Payload, Signature
1. Header
说一下我是什么
header通常包含了两部分:类型和加密算法
{
"alg": "HS256",
"typ": "JWT"
}
header需要经过Base64Url编码后作为IWT的第一部分。
2. Payload
payload包含了claim, 三种类型reserved, public, private
reserved这些claim是JWT预先定义的,不强制使用,常用的有:
1). iss: 签发者
2). exp: 过期的时间戳
3). sub: 面向的用户
4). aud: 接收方
5). iat: 签发时间
{
"sub": "1234567890",
"name": "John Doe",
"admin": true
}
payload需要经过Base64Url编码后作为JWT的第二部分。
3. Signature
创建签名使用编码后的header和payload以及一个密匙,使用header中指定的签名算法进行签名
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret
)
签名是在服务端进行的,客户端并不知道,所以是安全的。
JWT如何实现登录、鉴权JWT(JSON WEB TOKEN):JSON网络令牌,JWT是一个轻便的安全跨平台传输格式,定义了一个紧凑的自包含的方式在不同实体之间安全传输信息(JSON格式)。它是在Web环境下两个实体之间传输数据的一项标准。实际上传输的就是一个字符串。广义上讲JWT是一个标准的名称;狭义上JWT指的就是用来传递的那个token字符串。
由于http协议是无状态的,所以可以认为客户端和服务端的所有交互都是新的请求,这就意味着当我们通过账号密码验证用户时,当下一个request请求时它就不会携带刚刚的资料,于是程序只能再次重新识别。JWT就是实现了以JSON的格式,在客户端和服务端安全的传输供认证使用的信息。
根据http协议,我们并不能知道是哪个用户发出的请求,所以为了让应用能识别,我们只能在服务器存储一份用户登录的信息,这份登录信息会在响应时传递给浏览器保存为cookie,以便下次请求时发送给应用,这样应用就能识别请求来自哪个用户了,这就是传统的基于session认证。
但是session是保存到服务器内存当中的,不能跨应用服务器共享,使得应用很难扩展,随着客户端用户量增加,独立的服务器已无法承载更多的用户,这是基于session身份认证方案的问题就会暴露出来,并且这种方案存在CSRF风险,因此随着技术的发展就有了基于Token身份认证的方案去解决这些问题。
基于token的鉴权机制类似于http协议也是无状态的,它不需要在服务端去保留用户的认证信息或者会话信息。这就意味着基于token认证机制的应用不需要去考虑用户在哪一台服务器登录了,这就为应用的扩展提供了便利,另外因为用户的信息是保存在分布式缓存中,这种方式就支持分布式水平扩展,支持高并发。
由于token是保存在Redis服务器中,使用这种方式无疑加大了对Redis缓存组件的依赖和增加了硬件资源的投资。
那么我们开始介绍JWT的特点。
服务端验证后,将部分的用户信息存放到JWT中,也就是存在token的字符串中,比如用户的email和用户的姓名等。在鉴权的流程当中,是直接从JWT中直接获取用户信息,这样减少了对Redis缓存组件的依赖,也减少了硬件资源的投入。
优点:
安全性高,防止token被伪造和篡改
自包含,减少存储开销
跨语言,支持多种语言实现
支持过期,发布者等校验
缺点:
JWT不适用存放大量信息,会造成token过长
无法作废未过期的JWT,所以需要搭配Redis使用,达到用户登出操作token即失效的要求。
一个JWT是一个字符串,其由Header(头部)、Payload(负载)和Signature(签名)三个部分组成,中间以.号分隔,其格式为Header.Payload.Signature。
按照header.payload.signature这个格式串起来,串之前注意,header和payload也要做一个base64url encoded的转换。那么最终拼出来的一个例子是:
JWT指定了七个默认claims字段供选择。
iss:发行人
sub:主题
aud:用户
exp:到期时间
nbf:在此之前不可用
iat:发布时间
jti:JWT ID用于标识该JWT
除以上默认字段外,我们还可以自定义私有字段,如下例:
{
"sub":"8208208820",
"name":"hubert",
"role":"admin"
}
按照JWT标准的说明:保留的claims都是可选的,在生成payload不强制用上面的那些claim,另外你可以按照自己的想法来定义payload的结构,不过这样搞根本没必要:第一是,如果把JWT用于认证, 那么JWT标准内规定的几个claim就足够用了,假如想往JWT里多存一些用户业务信息,比如用户名(name)和角色(role)等才需要考虑添加自定义claim;第二是,JWT标准里面针对它自己规定的claim都提供了有详细的验证规则描述,每个实现库都会参照这个描述来提供JWT的验证实现,所以如果是自定义的claim名称,那么你用到的实现库就不会主动去验证这些claim。
根据源码可以发现在校验过程中主要是校验JWT字符串的格式、过期时间、加密算法正确性等。
具体校验的源码:
1 发送JWT要用https,因为JWT本身无法保证数据安全性
2 JWT的payload中不要包含太多用户信息,特别是权限角色的信息。
3 JWT的payload中建议设定一个expire时间,且不能设置太长,为什么要设置其实和cookie为什么设置过期时间一样,都是为了安全,JWT一旦生成发出去就不可以更改,在有效期内就可以永久使用。
JWT 认证过程A JWT token contains a Header, a Payload, and a Signature.
Header
Header contains the algorithms like RSA or HMACSHA256 and the information of the type of Token.
Payload
Payload contains the information of rows, i.e., user credentials.
How Does JWT Work?
Step 1
Client logs in with his/her credentials.
Step 2
Server generates a Jwt token at server side.
Step 3
After token generation, the server returns a token in response.
Step 4
Now, the client sends a copy of the token to validate the token.
Step 5
The server checks JWT token to see if it's valid or not.
Step 6
After the token is validated, the server sends a status message to the client.
[图片上传中...(-4ee818-1642837712343-0)]
授权流程:
1、用户请求登录,携带用户名密码到授权中心
2、授权中心携带用户名密码,到用户中心查询用户
3、查询如果正确,生成JWT凭证
4、返回JWT给用户
鉴权流程:
1、用户请求某微服务功能,携带JWT
2、微服务将jwt交给授权中心校验
3、授权中心返回校验结果到微服务
4、微服务判断校验结果,成功或失败
5、失败则直接返回401
6、成功则处理业务并返回
SpringSecurity+JWT认证流程解析本文适合: 对Spring Security有一点了解或者跑过简单demo但是对整体运行流程不明白的同学,对SpringSecurity有兴趣的也可以当作你们的入门教程,示例代码中也有很多注释。
大家在做系统的时候,一般做的第一个模块就是 认证与授权 模块,因为这是一个系统的入口,也是一个系统最重要最基础的一环,在认证与授权服务设计搭建好了之后,剩下的模块才得以安全访问。
市面上一般做认证授权的框架就是shiro和Spring Security,也有大部分公司选择自己研制。出于之前看过很多Spring Security的入门教程,但都觉得讲的不是太好,所以我这两天在自己鼓捣Spring Security的时候萌生了分享一下的想法,希望可以帮助到有兴趣的人。
Spring Security框架我们主要用它就是解决一个认证授权功能,所以我的文章主要会分为两部分:
我会为大家用一个Spring Security + JWT + 缓存的一个demo来展现我要讲的东西,毕竟脑子的东西要体现在具体事物上才可以更直观的让大家去了解去认识。
学习一件新事物的时候,我推荐使用自顶向下的学习方法,这样可以更好的认识新事物,而不是盲人摸象。
注 :只涉及到用户认证授权不涉及oautstrong之类的第三方授权。
想上手 Spring Security 一定要先了解它的工作流程,因为它不像工具包一样,拿来即用,必须要对它有一定的了解,再根据它的用法进行自定义操作。
我们可以先来看看它的工作流程:
在Spring Security的官方文档上有这么一句话:
Spring Security 的web基础是Filters。
这句话展示了Spring Security的设计思想: 即通过一层层的Filters来对web请求做处理。
放到真实的Spring Security中,用文字表述的话可以这样说:
一个web请求会经过一条过滤器链,在经过过滤器链的过程中会完成认证与授权,如果中间发现这条请求未认证或者未授权,会根据被保护API的权限去抛出异常,然后由异常处理器去处理这些异常。
用图片表述的话可以这样画,这是我在百度找到的一张图片:
如上图,一个请求想要访问到API就会以从左到右的形式经过蓝线框框里面的过滤器,其中绿色部分是我们本篇主要讲的负责认证的过滤器,蓝色部分负责异常处理,橙色部分则是负责授权。
图中的这两个绿色过滤器我们今天不会去说,因为这是Spring Security对form表单认证和Basic认证内置的两个Filter,而我们的demo是JWT认证方式所以用不上。
如果你用过Spring Security就应该知道配置中有两个叫formLogin和httpBasic的配置项,在配置中打开了它俩就对应着打开了上面的过滤器。
换言之,你配置了这两种认证方式,过滤器链中才会加入它们,否则它们是不会被加到过滤器链中去的。
因为Spring Security自带的过滤器中是没有针对JWT这种认证方式的,所以我们的demo中会 写一个JWT的认证过滤器,然后放在绿色的位置进行认证工作。
知道了Spring Security的大致工作流程之后,我们还需要知道一些非常重要的概念也可以说是组件:
上下文对象,认证后的数据就放在这里面,接口定义如下:
这个接口里面只有两个方法,其主要作用就是get or set Authentication。
可以说是SecurityContext的工具类,用于get or set or clear SecurityContext,默认会把数据都存储到当前线程中。
这几个方法效果如下:
Authentication只是定义了一种在SpringSecurity进行认证过的数据的数据形式应该是怎么样的,要有权限,要有密码,要有身份信息,要有额外信息。
AuthenticationManager定义了一个认证方法,它将一个未认证的Authentication传入,返回一个已认证的Authentication,默认使用的实现类为:ProviderManager。
接下来大家可以构思一下如何将这四个部分,串联起来,构成Spring Security进行认证的流程:
1. 先是一个请求带着身份信息进来
2. 经过AuthenticationManager的认证,
3. 再通过SecurityContextHolder获取SecurityContext,
4. 最后将认证后的信息放入到SecurityContext。
真正开始讲诉我们的认证代码之前,我们首先需要导入必要的依赖,数据库相关的依赖可以自行选择什么JDBC框架,我这里用的是国人二次开发的myabtis-plus。
接着,我们需要定义几个必须的组件。
由于我用的Spring-Boot是2.X所以必须要我们自己定义一个加密器:
这个Bean是不必可少的,Spring Security在认证操作时会使用我们定义的这个加密器,如果没有则会出现异常。
实现UserDetailsService的抽象方法并返回一个 UserDetails 对象,认证过程中SpringSecurity会调用这个方法访问数据库进行对用户的搜索,逻辑什么都可以自定义,无论是从数据库中还是从缓存中,但是我们需要将我们查询出来的用户信息和权限信息组装成一个 UserDetails 返回。
UserDetails 也是一个定义了数据形式的接口,用于保存我们从数据库中查出来的数据,其功能主要是验证账号状态和获取权限,具体实现可以查阅我仓库的代码。
由于我们是JWT的认证模式,所以我们也需要一个帮我们操作Token的工具类,一般来说它具有以下三个方法就够了:
在下文我的代码里面,JwtProvider充当了Token工具类的角色,具体实现可以查阅我仓库的代码。
有了前面的讲解之后,大家应该都知道用SpringSecurity做JWT认证需要我们自己写一个过滤器来做JWT的校验,然后将这个过滤器放到绿色部分。
在我们编写这个过滤器之前,我们还需要进行一个认证操作,因为我们要先访问认证接口拿到token,才能把token放到请求头上,进行接下来请求。
如果你不太明白,不要紧,先接着往下看我会在这节结束再次梳理一下。
访问一个系统,一般最先访问的是认证方法,这里我写了最简略的认证需要的几个步骤,因为实际系统中我们还要写登录记录啊,前台密码解密啊这些操作。
这里一共五个步骤,大概只有前四步是比较陌生的:
这样的话就算完成了,感觉上很简单,因为主要认证操作都会由authenticationManager.authenticate()帮我们完成。
接下来我们可以看看源码,从中窥得Spring Security是如何帮我们做这个认证的(省略了一部分):
看了源码之后你会发现和我们平常写的一样,其主要逻辑也是查数据库然后对比密码。
登录之后效果如下:
我们返回token之后,下次请求其他API的时候就要在请求头中带上这个token,都按照JWT的标准来做就可以。
有了token之后,我们要把过滤器放在过滤器链中,用于解析token,因为我们没有session,所以我们每次去辨别这是哪个用户的请求的时候,都是根据请求中的token来解析出来当前是哪个用户。
所以我们需要一个过滤器去拦截所有请求,前文我们也说过,这个过滤器我们会放在绿色部分用来替代UsernamePasswordAuthenticationFilter,所以我们新建一个JwtAuthenticationTokenFilter,然后将它注册为Bean,并在编写配置文件的时候需要加上这个:
addFilterBefore的语义是添加一个Filter到XXXFilter之前,放在这里就是把JwtAuthenticationTokenFilter放在UsernamePasswordAuthenticationFilter之前,因为filter的执行也是有顺序的,我们必须要把我们的filter放在过滤器链中绿色的部分才会起到自动认证的效果。
接下来我们可以看看JwtAuthenticationTokenFilter的具体实现了:
代码里步骤虽然说的很详细了,但是可能因为代码过长不利于阅读,我还是简单说说,也可以直接去仓库查看源码:
这样的话,每一个带有正确token的请求进来之后,都会找到它的账号信息,并放在上下文对象中,我们可以使用SecurityContextHolder很方便的拿到上下文对象中的Authentication对象。
完成之后,启动我们的demo,可以看到过滤器链中有以下过滤器,其中我们自定义的是第5个:
就酱,我们登录完了之后获取到的账号信息与角色信息我们都会放到缓存中,当带着token的请求来到时,我们就把它从缓存中拿出来,再次放到上下文对象中去。
结合认证方法,我们的逻辑链就变成了:
登录拿到token请求带上tokenJWT过滤器拦截校验token将从缓存中查出来的对象放到上下文中
这样之后,我们认证的逻辑就算完成了。
认证和JWT过滤器完成后,这个JWT的项目其实就可以跑起来了,可以实现我们想要的效果,如果想让程序更健壮,我们还需要再加一些辅助功能,让代码更友好。
当用户未登录或者token解析失败时会触发这个处理器,返回一个非法访问的结果。
当用户本身权限不满足所访问API需要的权限时,触发这个处理器,返回一个权限不足的结果。
用户退出一般就是清除掉上下文对象和缓存就行了,你也可以做一下附加操作,这两步是必须的。
JWT的项目token刷新也是必不可少的,这里刷新token的主要方法放在了token工具类里面,刷新完了把缓存重载一遍就行了,因为缓存是有有效期的,重新put可以重置失效时间。
这篇文我从上周日就开始构思了,为了能讲的老妪能解,修修改改了几遍才发出来。
作者:和耳朵
链接:
关于php如何认证jwt的介绍到此就结束了,不知道本篇文章是否对您有帮助呢?如果你还想了解更多此类信息,记得收藏关注本站,我们会不定期更新哦。
查看更多关于php如何认证jwt php basic认证的详细内容...