JWT是json web token缩写。它将用户信息加密到token里,服务器不保存任何用户信息。服务器通过使用保存的密钥验证token的正确性,只要正确即通过验证。基于token的身份验证可以替代传统的cookie+session身份验证方法。
代码来自网络,亲测有效,所以记录一下
JWT由三个部分组成:header.payload.signature
该字段为json格式,alg字段指生成signature的算法,默认值为
HS256,typ默认值为JWT
{
"alg": "HS256",
"typ": "JWT"
}
该字段为json格式,表明用户身份的数据,可以根据业务需求自行定义
{
"username": "admin", //该JWT的签发者
"exp": 1535974630, //过期时间,系统当前时间*
}
签名算法,一般为HS256,其他的算法怎么整,具体长啥样儿我也不知道,没有找到,郁闷
以加密方式为
HS256为例
header进行base64UrlEncode加密后的字符串–字符串1
base64UrlEncode(header)
payload的内容进行base64UrlEncode加密后的字符串–字符串2
base64UrlEncode(payload)
字符串1+'.'+字符串2拼接成一个新的字符串–字符串3
base64UrlEncode(header)+’.’+base64UrlEncode(payload)
通过header中的指定的算法来对字符串3 和一个密钥secret进行HMacSHA256()进行加密得到一个新的字符串就是jwt的主要内容
//java
//HMACSHA256签名 https://jwt.io/introduction 中HMACSHA
HMacSHA256(
base64UrlEncode(header) + '.'
+ base64UrlEncode(payload)
+ secret)
主要是用pyjwt这个包来实现加解密
# pip3 install pyjwt
import jwt
import datetime
from jwt import exceptions
JWT_SALT = 'ashlkdjfhoawhe;kfjnasdlkfjlasdhfoiuahsdvlajksnd'
def create_token(payload, timeout=20):
"""
:param payload: 例如:{'user_id':1,'username':'sinmu'}用户信息
:param timeout: token的过期时间,默认20s
:return:
"""
headers = {
'typ': 'jwt',
'alg': 'HS256'
}
payload['exp'] = datetime.datetime.utcnow() + datetime.timedelta(seconds=timeout)
tmp = jwt.encode(payload=payload, key=JWT_SALT, algorithm="HS256", headers=headers)
result = tmp.encode('utf-8')
return result
def parse_payload(token):
"""
对token进行和发行校验并获取payload
:param token:
:return:
"""
result = {'status': False, 'data': None, 'error': None}
try:
verified_payload = jwt.decode(token, JWT_SALT, algorithms="HS256")
result['status'] = True
result['data'] = verified_payload
except exceptions.ExpiredSignatureError:
result['error'] = 'token已失效'
except jwt.DecodeError:
result['error'] = 'token认证失败'
except jwt.InvalidTokenError:
result['error'] = '非法的token'
return result
if __name__ == '__main__':
token = create_token({'uid': 1, 'username': 'sinmu'},3).decode('utf-8')
res = parse_payload(token)
print(res)
import io.jsonwebtoken.*;
import java.util.Date;
public class JwtUtils {
private long expire=7200;
private String secret="dwhidhkwhdkdiwhd232323dwdadwdw2a";
private String header="Authorization";
// 生成jwt
public String generateToken(String username) {
Date nowDate = new Date();
Date expireDate = new Date(nowDate.getTime() + 1000 * expire);
return Jwts.builder()
.setHeaderParam("typ", "JWT")
.setSubject(username)
.setIssuedAt(nowDate)
.setExpiration(expireDate)// 两小时过期
.signWith(SignatureAlgorithm.HS512, secret)
.compact();
}
// 解析jwt
public Claims getClaimByToken(String jwt) {
try {
return Jwts.parser()
.setSigningKey(secret)
.parseClaimsJws(jwt)
.getBody();
} catch (Exception e) {
return null;
}
}
// jwt是否过期
public boolean isTokenExpired(Claims claims) {
return claims.getExpiration().before(new Date());
}
}
<?php
/**
* PHP实现jwt
*/
class Jwt {
//头部
private static $header=array(
'alg'=>'HS256', //生成signature的算法
'typ'=>'JWT' //类型
);
//使用HMAC生成信息摘要时所使用的密钥
private static $key='123456';
/**
* 获取jwt token
* @param array $payload jwt载荷 格式如下非必须
* [
* 'iss'=>'jwt_admin', //该JWT的签发者
* 'iat'=>time(), //签发时间
* 'exp'=>time()+7200, //过期时间
* 'nbf'=>time()+60, //该时间之前不接收处理该Token
* 'sub'=>'www.admin.com', //面向的用户
* 'jti'=>md5(uniqid('JWT').time()) //该Token唯一标识
* ]
* @return bool|string
*/
public static function getToken(array $payload)
{
if(is_array($payload))
{
$base64header=self::base64UrlEncode(json_encode(self::$header,JSON_UNESCAPED_UNICODE));
$base64payload=self::base64UrlEncode(json_encode($payload,JSON_UNESCAPED_UNICODE));
$token=$base64header.'.'.$base64payload.'.'.self::signature($base64header.'.'.$base64payload,self::$key,self::$header['alg']);
return $token;
}else{
return false;
}
}
/**
* 验证token是否有效,默认验证exp,nbf,iat时间
* @param string $Token 需要验证的token
* @return bool|string
*/
public static function verifyToken(string $Token)
{
$tokens = explode('.', $Token);
if (count($tokens) != 3)
return false;
list($base64header, $base64payload, $sign) = $tokens;
//获取jwt算法
$base64decodeheader = json_decode(self::base64UrlDecode($base64header), JSON_OBJECT_AS_ARRAY);
if (empty($base64decodeheader['alg']))
return false;
//签名验证
if (self::signature($base64header . '.' . $base64payload, self::$key, $base64decodeheader['alg']) !== $sign)
return false;
$payload = json_decode(self::base64UrlDecode($base64payload), JSON_OBJECT_AS_ARRAY);
//签发时间大于当前服务器时间验证失败
if (isset($payload['iat']) && $payload['iat'] > time())
return false;
//过期时间小宇当前服务器时间验证失败
if (isset($payload['exp']) && $payload['exp'] < time())
return false;
//该nbf时间之前不接收处理该Token
if (isset($payload['nbf']) && $payload['nbf'] > time())
return false;
return $payload;
}
/**
* base64UrlEncode https://jwt.io/ 中base64UrlEncode编码实现
* @param string $input 需要编码的字符串
* @return string
*/
private static function base64UrlEncode(string $input)
{
return str_replace('=', '', strtr(base64_encode($input), '+/', '-_'));
}
/**
* base64UrlEncode https://jwt.io/ 中base64UrlEncode解码实现
* @param string $input 需要解码的字符串
* @return bool|string
*/
private static function base64UrlDecode(string $input)
{
$remainder = strlen($input) % 4;
if ($remainder) {
$addlen = 4 - $remainder;
$input .= str_repeat('=', $addlen);
}
return base64_decode(strtr($input, '-_', '+/'));
}
/**
* HMACSHA256签名 https://jwt.io/ 中HMACSHA256签名实现
* @param string $input 为base64UrlEncode(header).".".base64UrlEncode(payload)
* @param string $key
* @param string $alg 算法方式
* @return mixed
*/
private static function signature(string $input, string $key, string $alg = 'HS256')
{
$alg_config=array(
'HS256'=>'sha256'
);
# HS256=> HASH_HMAC(SHA256,string,secret,true)
return self::base64UrlEncode(hash_hmac($alg_config[$alg], $input, $key,true));
}
}
//测试和官网是否匹配begin
$payload=array('uid'=>1,'name'=>'sinmu','iat'=>1516239022);
$jwt=new Jwt;
$token=$jwt->getToken($payload);
echo "<pre>";
echo $token;
//对token进行验证签名
$getPayload=$jwt->verifyToken($token);
echo "<br><br>";
var_dump($getPayload);
echo "<br><br>";
//测试和官网是否匹配end
//自己使用测试begin
$payload_test=array('iss'=>'admin','iat'=>time(),'exp'=>time()+7200,'nbf'=>time(),'sub'=>'www.admin.com','jti'=>md5(uniqid('JWT').time()));;
$token_test=Jwt::getToken($payload_test);
echo "<pre>";
echo $token_test;
//对token进行验证签名
$getPayload_test=Jwt::verifyToken($token_test);
echo "<br><br>";
var_dump($getPayload_test);
echo "<br><br>";
//自己使用时候end
我正在尝试测试是否存在表单。我是Rails新手。我的new.html.erb_spec.rb文件的内容是:require'spec_helper'describe"messages/new.html.erb"doit"shouldrendertheform"dorender'/messages/new.html.erb'reponse.shouldhave_form_putting_to(@message)with_submit_buttonendendView本身,new.html.erb,有代码:当我运行rspec时,它失败了:1)messages/new.html.erbshou
我在从html页面生成PDF时遇到问题。我正在使用PDFkit。在安装它的过程中,我注意到我需要wkhtmltopdf。所以我也安装了它。我做了PDFkit的文档所说的一切......现在我在尝试加载PDF时遇到了这个错误。这里是错误:commandfailed:"/usr/local/bin/wkhtmltopdf""--margin-right""0.75in""--page-size""Letter""--margin-top""0.75in""--margin-bottom""0.75in""--encoding""UTF-8""--margin-left""0.75in""-
我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t
我正在寻找执行以下操作的正确语法(在Perl、Shell或Ruby中):#variabletoaccessthedatalinesappendedasafileEND_OF_SCRIPT_MARKERrawdatastartshereanditcontinues. 最佳答案 Perl用__DATA__做这个:#!/usr/bin/perlusestrict;usewarnings;while(){print;}__DATA__Texttoprintgoeshere 关于ruby-如何将脚
我有一个对象has_many应呈现为xml的子对象。这不是问题。我的问题是我创建了一个Hash包含此数据,就像解析器需要它一样。但是rails自动将整个文件包含在.........我需要摆脱type="array"和我该如何处理?我没有在文档中找到任何内容。 最佳答案 我遇到了同样的问题;这是我的XML:我在用这个:entries.to_xml将散列数据转换为XML,但这会将条目的数据包装到中所以我修改了:entries.to_xml(root:"Contacts")但这仍然将转换后的XML包装在“联系人”中,将我的XML代码修改为
为了将Cucumber用于命令行脚本,我按照提供的说明安装了arubagem。它在我的Gemfile中,我可以验证是否安装了正确的版本并且我已经包含了require'aruba/cucumber'在'features/env.rb'中为了确保它能正常工作,我写了以下场景:@announceScenario:Testingcucumber/arubaGivenablankslateThentheoutputfrom"ls-la"shouldcontain"drw"假设事情应该失败。它确实失败了,但失败的原因是错误的:@announceScenario:Testingcucumber/ar
我在我的项目中添加了一个系统来重置用户密码并通过电子邮件将密码发送给他,以防他忘记密码。昨天它运行良好(当我实现它时)。当我今天尝试启动服务器时,出现以下错误。=>BootingWEBrick=>Rails3.2.1applicationstartingindevelopmentonhttp://0.0.0.0:3000=>Callwith-dtodetach=>Ctrl-CtoshutdownserverExiting/Users/vinayshenoy/.rvm/gems/ruby-1.9.3-p0/gems/actionmailer-3.2.1/lib/action_mailer
我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server
在MRIRuby中我可以这样做:deftransferinternal_server=self.init_serverpid=forkdointernal_server.runend#Maketheserverprocessrunindependently.Process.detach(pid)internal_client=self.init_client#Dootherstuffwithconnectingtointernal_server...internal_client.post('somedata')ensure#KillserverProcess.kill('KILL',
我已经从我的命令行中获得了一切,所以我可以运行rubymyfile并且它可以正常工作。但是当我尝试从sublime中运行它时,我得到了undefinedmethod`require_relative'formain:Object有人知道我的sublime设置中缺少什么吗?我正在使用OSX并安装了rvm。 最佳答案 或者,您可以只使用“require”,它应该可以正常工作。我认为“require_relative”仅适用于ruby1.9+ 关于ruby-主要:Objectwhenrun