什么是JWT
JSON Web Token是一个开发标准(RFC 7519),定义了一个紧凑且独立的方式,可以将各方之间的信息作为JSON对象进行安全传输,该信息可以验证和信任,因为是经过数字签名的。
JWT是JSON Web Token的缩写,是一种轻量级的身份验证和授权的标准。
它通过在用户登录后生成一个包含用户信息和过期时间等数据的JSON格式令牌,并将其使用密钥进行加密,然后在之后的请求中将该令牌发送给服务器,服务器可以根据令牌中的信息验证用户身份并进行授权操作。
更多精彩内容,请微信搜索“前端爱好者
“, 戳我 查看 。
JWT部分组成
JWT 由三部分组成,分别是
- 头部(Header)、
- 载荷(Payload)
- 签名(Signature)。
头部通常用于描述 JWT 的元数据,如算法类型、token 类型等信息,采用 Base64 编码。
- typ:token的类型,这里固定为JWT
- alg:使用的hash算法,例如 HMAC SHA256 或者 RSA
载荷是 JWT 实际要传输的内容,通过 Base64 编码进行传输。载荷中可以包含各种声明,如用户 ID、角色、权限等信息。
签名用于验证消息的完整性和真实性,可以使用 HMAC 算法或者 RSA 签名算法生成,由头部和载荷一起进行签名,防止 token 被篡改。
Signature = HMACSHA256(base64URLEncode(header) +"." + base64URLEncode(payload), secret)
JWT的优点
JWT的优点包括:
- 使用简单、
- 跨平台支持、
- 可进行自定义扩展等
但也需要注意,在使用JWT时,我们需要在服务器端妥善保管密钥
,并根据实际情况设置过期时间
,以防止信息泄露和失效等问题。
JWT工作原理
- 用户通过用户名和密码等进行身份验证后,服务器端根据验证结果生成一个包含用户信息(如用户ID、角色等)以及其他辅助信息(如过期时间等)的JSON格式的令牌。服务器使用密钥将令牌进行签名,生成一个JWT。
- 签名后的JWT可以被发送到客户端,并保存在客户端的缓存、Cookie或本地存储中。
- 客户端在后续的请求中,将JWT发送到服务器,以表明其具有相应的授权。
- 服务器对JWT进行验证,检查是否为有效签名、是否过期并确保令牌中包含的用户信息可以满足该请求的要求。如果JWT验证通过,则表示用户已被授权执行特定操作。
总体来说,JWT就是一种安全性较高的身份验证和授权方式。它使用了标准的JSON格式进行数据传输,并利用密钥进行加密和签名,能够更好地保护用户信息和防止非法访问。
生成 JWT 示例
头部(Header):
{
"alg": "HS256",
"typ": "JWT"
}
载荷(Payload):
{
"sub": "1234567890",
"name": "john doe",
"iat": 1516239022
}
签名(Signature):
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret)
其中 secret 是用于生成签名的密钥。
最终 JWT Token:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6ImpvaG4gZG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
这个 JWT 将用户 ID、用户名以及 token 的创建时间作为了载荷,使用 HMACSHA256 算法和密钥生成签名。
在应用中,当需要进行身份验证时,可以通过解密 JWT 并验证签名来确定用户的身份和权限。
生成和验证 JWT 的示例
以下是一个用于生成和验证 JWT 的示例代码:
const jwt = require('jsonwebtoken');
const secret = 'mysecret'; // 秘钥,用于签名
// 生成 JWT
const user = { id: 1, name: 'Alice' };
const token = jwt.sign(user, secret, { expiresIn: '1h' });
console.log(token); // 输出生成的 JWT 字符串
// 验证 JWT
jwt.verify(token, secret, (err, decoded) => {
if (err) {
console.error(err);
} else {
console.log(decoded); // 输出解码后的用户信息
}
});
在上面的示例中,jsonwebtoken 模块 提供了 sign 和 verify 方法用于生成和验证 JWT。
首先在代码中定义了一个秘钥 secret 用于签名,然后通过 jwt.sign 方法将用户信息和秘钥使用指定的算法进行加密,生成一个 JWT 字符串。其中,expiresIn 参数指定了 JWT 的有效期。
接着,在代码中调用 jwt.verify 方法对 JWT 进行验证,如果没有错误则解密 JWT 并输出解码后的用户信息。如果验证失败,则会输出错误信息。
需要注意的是, 在 JWT 的生成和使用过程中,秘钥需要保密,并且只在服务端保存
。此外,也需要注意 JWT 的有效期设置,及时更新并过期失效以避免安全问题。
完整示例:用户登录和token验证
let jwt = require('jsonwebtoken')
let Users = require('../model/users')
/**
* 用户登录
*/
const login = async ctx => {
let {username,pwd} = ctx.request.body
await Users.findOne({username,pwd}).then(rel=>{
if(rel){
let token = jwt.sign({
username: rel.username,
_id: rel._id
},'server-jwt',{
expiresIn: 3600 * 24 * 7
})
ctx.body = {
code: 200,
msg: '登录成功',
token
}
}else{
ctx.body = {
code: 300,
msg: '用户名或密码错误'
}
}
}).catch(err=>{
ctx.body = {
code: 500,
msg: '登录时出现异常',
err
}
})
}
/**
* 验证用户登录
*/
const verify = async ctx => {
let token = ctx.header.authorization
token = token.replace('Bearer ','')
try{
let result = jwt.verify(token, 'jianshu-server-jwt')
await Users.findOne({_id:result._id}).then(rel=>{
if(rel){
ctx.body = {
code: 200,
msg: '用户认证成功',
user: rel
}
}else{
ctx.body = {
code: 500,
msg: '用户认证失败'
}
}
}).catch(err=>{
ctx.body = {
code: 500,
msg: '用户认证失败'
}
})
}catch(err) {
ctx.body = {
code: 500,
msg: '用户认证失败'
}
}
}
module.exports = {
login,
verify
}
koa 接口如何设置不进行jwt校验
在 Koa 中,可以使用 koa-jwt 这个中间件来进行 JWT 的校验。如果你想在某些接口中不进行 JWT 校验,可以通过以下两种方式来实现:
方式一:忽略单个路由
你可以在某个路由的处理函数中直接跳过 JWT 校验,例如:
router.get('/public', async (ctx, next) => {
// 这些接口不需要JWT认证,直接通过
await next();
});
这样,当请求 /public 这个接口时,Koa 将直接调用下一个中间件,而不进行 JWT 校验。
方式二:忽略多个路由
你也可以使用“或”操作符 | 来设置多个路由,从而忽略它们的 JWT 校验。例如:
const jwt = require('koa-jwt');
const { secret } = require('./config');
// 在初始化路由前,加上这段代码,表示 /login 和 /register 路由不进行JWT校验
app.use(jwt({ secret }).unless({ path: [/^\/login/, /^\/register/] }));
这里的 unless 方法是 koa-jwt 提供的一个快捷方法,用于指定哪些路由不需要 JWT 校验。
通常情况下,在初始化路由之前使用这个方法就可以达到忽略 JWT 校验的效果。
每日一课:react常用知识点之一
React 是一个流行的 JavaScript 库,用于构建用户界面。以下是 React 的一些常见知识点:
组件:
组件是 React 中最重要的概念之一,它负责渲染 UI,并处理用户交互。
组件可以嵌套在其他组件中,形成一个层次结构。
组件可以是类组件或函数组件。
React 中的一切都是组件,它是应用程序中的一个独立单元。
组件可以被重用,并且可以嵌套在其他组件中。
React 中的组件有两种类型:
- 函数式组件和类组件。函数式组件是一个只接收 props 并返回 JSX 的函数,
- 类组件是一个继承 React.Component 并覆盖 render 方法的 ES6 类。
以下是一个简单的函数式组件的示例:
function Greeting(props) {
return <h1>Hello, {props.name}!</h1>;
}
这个组件接收一个 props 对象,并使用 props.name 渲染出一个问候语。
以下是一个类组件的示例:
class Counter extends React.Component {
constructor(props) {
super(props);
this.state = { count: 0 };
}
handleClick = () => {
this.setState((prevState) => ({ count: prevState.count + 1 }));
};
render() {
return (
<div>
<p>You clicked {this.state.count} times</p>
<button onClick={this.handleClick}>Click me</button>
</div>
);
}
}
这个组件有一个初始状态 count 等于 0,当点击按钮时,会更新 count 的值并重新渲染组件。
注意,在类组件中,我们使用了一个专门的状态对象来管理组件的状态,而不是直接使用 props 对象。
无论是函数式组件还是类组件,都是 React 中非常重要的概念,需要仔细理解和掌握。
JSX:
JSX 是一种类似 HTML 的语法,用于在 JavaScript 中描述用户界面。
JSX 是一种语法扩展,允许在 JavaScript 代码中嵌入 XML 标签。
React 使用 JSX 来描述组件的外观和功能,最终将其转换为普通的 JavaScript 代码。
通过使用 JSX,我们可以重用现有的 HTML 结构和 CSS 样式,并且能够更加直观地描述组件的结构和内容。
以下是一个简单的 JSX 示例:
const element = <h1>Hello, World!</h1>;
这个代码片段使用了一个
元素来创建一个 React 元素,并将其赋值给了一个变量。在这个例子中,我们使用了类似于 HTML 的语法来描述元素的结构和内容。
在实际开发中,我们可以使用 JSX 来创建任何类型的元素,包括HTML 元素、React 组件、甚至是其他的 JSX 元素。
以下是一个使用 JSX 来创建组件的示例:
function Greeting(props) {
return <h1>Hello, {props.name}!</h1>;
}
在这个组件中,我们使用了类似于 HTML 的语法来描述组件的结构和内容。同时,我们也可以使用花括号来插入 JavaScript 表达式,以便动态计算需要渲染的内容。
props 和 state:
props 和 state 是组件中最重要的概念。
props 是从父组件传递给子组件的数据,不会改变。
而 state 是组件内部自己管理的状态,可以随时改变。当 state 发生变化时,React 可以自动更新视图。
props 可以是任何类型的 JavaScript 数据,包括字符串、数字、布尔值、数组、对象等。
以下是一个使用 props 的示例:
function Greeting(props) {
return <h1>Hello, {props.name}!</h1>;
}
在这个例子中,我们定义了一个函数式组件 Greeting,并且将一个名为 name 的 prop 传递给它。
通过这个 prop,我们可以传递任何字符串给 Greeting 组件,并且在组件内部使用它来渲染问候语。
与 props 不同,state 是组件内部定义的可变状态。只有通过修改组件的 state,才能更新组件的视图。
以下是一个带有 state 的类组件的示例:
class Counter extends React.Component {
constructor(props) {
super(props);
this.state = { count: 0 };
}
handleClick = () => {
this.setState((prevState) => ({ count: prevState.count + 1 }));
};
render() {
return (
<div>
<p>You clicked {this.state.count} times</p>
<button onClick={this.handleClick}>Click me</button>
</div>
);
}
}
在这个例子中,我们定义了一个 Counter 组件,并且在其构造函数中初始化了一个状态 count 等于 0。
在按钮的点击事件处理函数中,我们通过调用 setState 方法来更新组件的状态,并且通过重渲染来更新组件的视图。
props 和 state 都是 React 中非常重要的概念,需要仔细理解和掌握。props 用于在组件之间传递数据,而 state 则用于内部管理组件的状态。在实际开发中,我们通常会同时使用 props 和 state 来构建复杂的组件和应用程序。