#创作灵感
记录一下简单的token使用,
token的好处
携带令牌(Token)进行登录后的身份验证和授权具有以下好处:
-
无状态性(Stateless):令牌是无状态的,服务器不需要在每个请求中保留用户的会话信息。这样可以减轻服务器的负担,并使系统更易于扩展。
-
安全性:令牌使用密钥进行签名,确保令牌的完整性和真实性。只有服务器持有正确的密钥才能对令牌进行验证,从而防止伪造和篡改。
-
跨域支持:令牌可以在跨域环境下进行传递,因为它们通常作为请求头或查询参数发送。这使得在分布式系统或前后端分离的架构中进行身份验证和授权变得更加方便。
-
可扩展性:令牌可以包含自定义的声明(Claims),用于存储用户的相关信息和权限。这些声明可以根据需要进行扩展,以满足特定业务需求。
-
减少数据库查询:一旦令牌被签发,服务器可以通过解析令牌来验证用户的身份和权限,而无需频繁地查询数据库。这提高了系统的性能和响应速度。
-
可撤销性:令牌可以设置过期时间,并且可以在服务器端进行撤销。如果需要注销用户或强制用户重新登录,只需使令牌失效即可。
总的来说,携带令牌进行登录后的身份验证和授权可以提供更安全、灵活和可扩展的解决方案,适用于各种类型的应用程序和系统。
为什么选择token
择令牌(Token)作为身份验证和授权机制有以下几个主要原因:
-
安全性:令牌使用密钥进行签名,确保令牌的完整性和真实性。只有服务器持有正确的密钥才能对令牌进行验证,从而防止伪造和篡改。相比传统的基于会话的身份验证方式,令牌提供了更高的安全性。
-
无状态性(Stateless):令牌是无状态的,服务器不需要在每个请求中保留用户的会话信息。这样可以减轻服务器的负担,并使系统更易于扩展。每个请求都包含了足够的信息(令牌)来验证用户的身份和权限,不需要在服务器端存储会话状态。
-
跨域支持:令牌可以在跨域环境下进行传递,因为它们通常作为请求头或查询参数发送。这使得在分布式系统或前后端分离的架构中进行身份验证和授权变得更加方便。令牌可以在不同的域之间进行传递,而不会受到同源策略的限制。
-
可扩展性:令牌可以包含自定义的声明(Claims),用于存储用户的相关信息和权限。这些声明可以根据需要进行扩展,以满足特定业务需求。令牌的灵活性使得可以在其中包含额外的信息,而不需要频繁地查询数据库。
-
移动设备支持:对于移动设备应用程序,使用令牌进行身份验证和授权更加方便。移动设备可以在每个请求中携带令牌,并将其存储在本地,无需频繁地输入用户名和密码。
在项目中的简单作用
流程图
实现步骤
1 生成token令牌
前端vue3+ts 为例子 发送登录接口
function submit() {
dynamicRefForm.value.validate().then(({ valid, errors }: any) => {
if (valid) {
console.log('success', dynamicForm);
Login(dynamicForm)
} else {
Toast.warn(errors[0].message);
console.log('error submit!!', errors);
}
});
}
const Login = async (data :{ username :string,password:string}) => {
console.log(data);
const result = await getLogin(data)
console.log(result.token);
sessionStorage.setItem("token",result.token)
}
将token保存到缓存中
axios使用的自封装,如果不清楚,看上个博客
以nodejs为例,在接口中,实现登录功能,成功之后生成token 返回前端
router.post("/login",(req,res)=>{
console.log(req.body.name);
// 验证登录的逻辑
let token = "Bearer" + " " +jwt.sign({name:req.body.name},'secretKey',{expiresIn:'1h'});
console.log(token);
res.send({token})
})
2在请求头中添加token
通过在控制台输出,以便我们良好的观察axios的请求头
axios.interceptors.request.use(
(config) => {
// 在发送请求之前做些什么
const token : string = sessionStorage.getItem("token") || ""
if (token.length>0) {
config.headers.Authorization = token
console.log(config);
return config
}else{
console.log(config);
return config
}
},
(error) => {
// 对请求错误做些什么
return Promise.reject(error)
}
)
3在App.js中加入express-jwt 进行解析
let expressJWT = require("express-jwt");
const authMiddleware = require("./routes/token/index")
app.use(express.static(path.join(__dirname, 'public')));
//白名单
app.use(cors());
// //配置验证token的中间件 express-jwt
app.use(expressJWT({
// //解析口令 需要和加密的时候保持一致
secret: "secretKey",
// 加密方式 SHA256 加密方式在express-jwt 里面叫做 HS256
algorithms: ["HS256"]
}).unless({
//不需要token认证的路由 注意:如果有一级路由 需要把路由写完整
path: ["/auth/register", "/login", "/auth/routerDetail", '/meeting/list', '/classroom/list','/auth/refresh', { url: /^\/upload/, methods: ["GET"] }]
}))
app.use("/users",authMiddleware)
app.use('/users', usersRouter);
4使用jwt解析,加入中间件
const jwt = require('jsonwebtoken');
const authMiddleware = async(req,res,next) =>{
const authHeader = req.headers.authorization;
if (authHeader) {
// 从 Authorization 头部提取令牌
const token = authHeader.split(' ')[1]
console.log(token);
try {
console.log(1);
// 验证并解析令牌
const data = jwt.verify(token, 'secretKey');
console.log(data);
// console.log(decodedToken);
// 在 req 对象中存储解析后的令牌数据,以便其他路由处理器可以访问
// req.user = decodedToken;
next();
} catch (error) {
// 令牌验证失败
return res.status(404).json({ message: 'Invalid token' });
}
} else {
// 缺少 Authorization 头部
return res.status(401).json({ message: 'Missing token' });
}
}
module.exports = authMiddleware;