前言:最近复习之前做的项目中包含的知识,看了之前看的视频的笔记,并结合自己的理解写下了这篇关于JWT知识的博客,希望能加深自己的印象以及帮助的诸位小伙伴儿们🤞🤞
如果有什么需要改进的地方还请大佬斧正😁
小威在此先感谢诸佬了👏👏

🏠个人主页:小威要向诸佬学习呀
🧑个人简介:大家好,我是小威,一个想要与大家共同进步的男人😉😉
目前状况🎉:目前大二,在一家满意的公司实习👏👏🎁如果大佬在准备面试,找工作,刷算法,可以使用我找实习前用的刷题神器哦刷题神器点这里哟
💕欢迎大家:这里是CSDN,我总结知识的地方,欢迎来到我的博客,我亲爱的大佬😘
以下正文开始

文章目录
单点登录的三种实现方式:分别为session广播机制;cookie+redis;token三种。session广播机制指在一个集群中的一个模块登录后,然后把该session复制成几份,发送到该集群的其他模块中,可以形成在个地方登录,其他地方不用再登录的效果。
参与集群的每个节点的Session状态都被复制到集群中的其他所有节点上,无论何时,只要Session发生改变,Session数据都要重新被复制。Tomcat、JBoss等都提供了这样的功能,其中Tomcat采用集群节点广播复制,JBoss采用配对复制机制。
Session广播机制优缺点:
优点:每个节点都复制一份Session,一个节点出现问题时其它节点可以接替它的工作。
缺点:节点间进行Session同步会占据大量系统资源,整体性能随着集群节点数的增加而下降。

用户在项目的任意一个模块登录后,登录之后,该模块会将用户的登录信息放到两个地方:redis 和 cookie 中。
系统会先将用户的登录信息存入 redis中,其在 redis 的 key 值是生成的唯一值 (可以包含 ip、用户 id、UUID等),value 值存放用户的登录信息。
接着系统会将这名用户在 redis 中的 key 值存入该用户的 cookie 中,用户每次访问任意模块时都会带着这个 cookie。
用户在访问其他模块发送请求时,会带着客户端的 cookie 进行请求,而客户端的 cookie 已经存入了该用户在 redis 中的 key 值,这样其他模块在处理用户的请求时,可以先获取用户 cookie中的 key 值,然后拿着这个 key 值到 redis 中进行查询,如果在 redis 中能查询到该用户相应的登录信息,就说明该用户已登录,就不需要用户进行重复登录了。
token 是按照一定规则生成的字符串,字符串中可以包含用户信息。开发人员可以自行定制这个生成规则,也可以使用提供好的生成规则(如使用 JWT 自动生成包含用户信息的字符串)。
用户在项目的某个模块进行登录后,系统会按照一定(或定制)的规则生成字符串,把用户登录之后的信息包含到这个生成的字符串中,然后系统可以将这个字符串返回,主要有两种返回方式:1.可以把字符串通过 cookie 返回;2.可以把字符串通过地址栏返回。
这样用户在访问其他的模块时,每次访问的地址栏都会带着生成的字符串
成字符串),然后根据字符串获取用户信息,如果可以获取到用户的登录信息,说明该用户已登录,用户就不需要重复登录了。
JWT生成的字符串包括三部分:
1.JWT头信息
2.有效载荷(包含头部信息)
3.签名哈希
JWT头
JWT头部分是一个描述JWT元数据的JSON对象,通常如下所示。
{
“alg”: “HS256”,
“type”: “JWT”
}
在上面的代码中,alg属性表示签名使用的算法,默认为HMAC SHA256(写为HS256);type属性表示令牌的类型,JWT令牌统一写为JWT。最后,使用Base64 URL算法将上述JSON对象转换为字符串保存。
有效载荷
有效载荷部分,是JWT的主体内容部分,也是一个JSON对象,包含需要传递的数据。 JWT指定七个默认字段供选择:
iss:发行人
exp:到期时间
sub:主题
aud:用户
nbf:在此之前不可用
iat:发布时间
jti:JWT ID用于标识该JWT
除以上默认字段外,我们还可以自定义私有字段,如下例:
{
"sub": "1234567890",
"name": "xiaowei",
"admin": true
}
默认情况下JWT是未加密的,任何人都可以解读其内容,因此不要构建隐私信息字段,存放保密信息,以防止信息泄露。
JSON对象也使用Base64 URL算法转换为字符串保存。
签名哈希
签名哈希部分是对上面两部分数据签名,通过指定的算法生成哈希,以确保数据不会被篡改。
首先,需要指定一个密码(secret)。该密码仅仅为保存在服务器中,并且不能向用户公开。然后,使用标头中指定的签名算法(默认情况下为HMAC SHA256)根据以下公式生成签名。

JWT的原则
JWT的原则是在服务器身份验证之后,将生成一个JSON对象并将其发送回用户,如下所示。
{
"sub": "1234567890",
"name": "xiaowei",
"admin": true
}
之后,当用户与服务器通信时,客户在请求中发回JSON对象。服务器仅依赖于这个JSON对象来标识用户。为了防止用户篡改数据,服务器将在生成对象时添加签名。
服务器不保存任何会话数据,即服务器变为无状态,使其更容易扩展。
JWT的用法
客户端接收服务器返回的JWT,将其存储在Cookie或localStorage中。
此后,客户端将在与服务器交互中都会带JWT。如果将它存储在Cookie中,就可以自动发送,但是不会跨域,因此一般是将它放入HTTP请求的Header Authorization字段中。当跨域时,也可以将JWT被放置于POST请求的数据主体中。

JWT不仅可用于认证,还可用于信息交换。善用JWT有助于减少服务器请求数据库的次数。
生产的token可以包含基本信息,比如id、用户昵称、头像等信息,避免再次查库 存储在客户端,不占用服务端的内存资源
JWT默认不加密,但可以加密。生成原始令牌后,可以再次对其进行加密。 当JWT未加密时,一些私密数据无法通过JWT传输。
JWT的最大缺点是服务器不保存会话状态,所以在使用期间不可能取消令牌或更改令牌的权限。也就是说,一旦JWT签发,在有效期内将会一直有效。
JWT本身包含认证信息,token是经过base64编码,所以可以解码,因此token加密前的对象不应该包含敏感信息,一旦信息泄露,任何人都可以获得令牌的所有权限。为了减少盗用,JWT的有效期不宜设置太长。对于某些重要操作,用户在使用时应该每次都进行进行身份验证。
为了减少盗用和窃取,JWT不建议使用HTTP协议来传输代码,而是使用加密的HTTPS协议进行传输。

首先在项目中添加依赖:
<dependencies>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
</dependency>
</dependencies>
创建JWT的工具类
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.util.StringUtils;
import javax.servlet.http.HttpServletRequest;
import java.util.Date;
public class JwtUtils {
public static final long EXPIRE = 1000 * 60 * 60 * 24;
public static final String APP_SECRET = "zkdlh8Ycvxmwd9sDxzc8czxcascX9";
public static String getJwtToken(String id, String nickname){
String JwtToken = Jwts.builder()
.setHeaderParam("type", "JWT")
.setHeaderParam("alg", "HS256")
.setSubject("guli-user")
.setIssuedAt(new Date())
.setExpiration(new Date(System.currentTimeMillis() + EXPIRE))
.claim("id", id)
.claim("nickname", nickname)
.signWith(SignatureAlgorithm.HS256, APP_SECRET)
.compact();
return JwtToken;
}
/**
* 判断token是否存在与有效
* @param jwtToken
* @return
*/
public static boolean checkToken(String jwtToken) {
if(StringUtils.isEmpty(jwtToken)) return false;
try {
Jwts.parser().setSigningKey(APP_SECRET).parseClaimsJws(jwtToken);
} catch (Exception e) {
e.printStackTrace();
return false;
}
return true;
}
/**
* 判断token是否存在与有效
* @param request
* @return
*/
public static boolean checkToken(HttpServletRequest request) {
try {
String jwtToken = request.getHeader("token");
if(StringUtils.isEmpty(jwtToken)) return false;
Jwts.parser().setSigningKey(APP_SECRET).parseClaimsJws(jwtToken);
} catch (Exception e) {
e.printStackTrace();
return false;
}
return true;
}
/**
* 根据token获取id
* @param request
* @return
*/
public static String getMemberIdByJwtToken(HttpServletRequest request) {
String jwtToken = request.getHeader("token");
if(StringUtils.isEmpty(jwtToken)) return "";
Jws<Claims> claimsJws = Jwts.parser().setSigningKey(APP_SECRET).parseClaimsJws(jwtToken);
Claims claims = claimsJws.getBody();
return (String)claims.get("id");
}
}
文章到这里就结束了,以后还会记录一些其他的知识,喜欢的大佬可以多多支持哦😉😉。
如果有什么疑问的地方请指出,诸佬们一起讨论🍻🍻

再次感谢各位小伙伴儿们的支持🤞

我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div
我有一个Ruby程序,它使用rubyzip压缩XML文件的目录树。gem。我的问题是文件开始变得很重,我想提高压缩级别,因为压缩时间不是问题。我在rubyzipdocumentation中找不到一种为创建的ZIP文件指定压缩级别的方法。有人知道如何更改此设置吗?是否有另一个允许指定压缩级别的Ruby库? 最佳答案 这是我通过查看rubyzip内部创建的代码。level=Zlib::BEST_COMPRESSIONZip::ZipOutputStream.open(zip_file)do|zip|Dir.glob("**/*")d
类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc
很好奇,就使用rubyonrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提
假设我做了一个模块如下:m=Module.newdoclassCendend三个问题:除了对m的引用之外,还有什么方法可以访问C和m中的其他内容?我可以在创建匿名模块后为其命名吗(就像我输入“module...”一样)?如何在使用完匿名模块后将其删除,使其定义的常量不再存在? 最佳答案 三个答案:是的,使用ObjectSpace.此代码使c引用你的类(class)C不引用m:c=nilObjectSpace.each_object{|obj|c=objif(Class===objandobj.name=~/::C$/)}当然这取决于
我正在尝试使用ruby和Savon来使用网络服务。测试服务为http://www.webservicex.net/WS/WSDetails.aspx?WSID=9&CATID=2require'rubygems'require'savon'client=Savon::Client.new"http://www.webservicex.net/stockquote.asmx?WSDL"client.get_quotedo|soap|soap.body={:symbol=>"AAPL"}end返回SOAP异常。检查soap信封,在我看来soap请求没有正确的命名空间。任何人都可以建议我
关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。
我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t
我想将html转换为纯文本。不过,我不想只删除标签,我想智能地保留尽可能多的格式。为插入换行符标签,检测段落并格式化它们等。输入非常简单,通常是格式良好的html(不是整个文档,只是一堆内容,通常没有anchor或图像)。我可以将几个正则表达式放在一起,让我达到80%,但我认为可能有一些现有的解决方案更智能。 最佳答案 首先,不要尝试为此使用正则表达式。很有可能你会想出一个脆弱/脆弱的解决方案,它会随着HTML的变化而崩溃,或者很难管理和维护。您可以使用Nokogiri快速解析HTML并提取文本:require'nokogiri'h
我想为Heroku构建一个Rails3应用程序。他们使用Postgres作为他们的数据库,所以我通过MacPorts安装了postgres9.0。现在我需要一个postgresgem并且共识是出于性能原因你想要pggem。但是我对我得到的错误感到非常困惑当我尝试在rvm下通过geminstall安装pg时。我已经非常明确地指定了所有postgres目录的位置可以找到但仍然无法完成安装:$envARCHFLAGS='-archx86_64'geminstallpg--\--with-pg-config=/opt/local/var/db/postgresql90/defaultdb/po