鉴权:生成token去进行鉴权

441 阅读3分钟

什么是鉴权,为什么要鉴权,鉴权有什么作用,相信很多做开发的小伙伴在平常开发过程都少不了鉴权这一环节,正所谓无规则不成方圆,每个平台都有自己的鉴权规则,什么样的角色能进行什么样的操作,什么样的操作只有特定的角色才能进行,举个简单的例子,一个很普通的双端系统,分别为用户端和管理员端,

image.png 当我们作为普通用户在使用在系统时,我们应该只能进行普通用户能够进行的操作,同样的,当我们作为管理员在使用这个系统时也应该只能进行管理员能够进行的操作,如果不对这些权限加以限制,普通用户能够进行管理员的操作,那整个系统不就乱套了,如果这个系统还上线使用了,甚至可能还会因为权限没有限制住而产生了比较严重的问题,那我们怎么样将这些权限给限制住呢,这就需要我们给系统进行鉴权了,我们可以利用token去进行鉴权,每个用户应该都有自己对应的用户特征,例如用户id,当用户等登录系统时,我们先对用户身份进行验证,验证成功后,服务端给客户端发送一个token,这个token里面保存了用户的身份特征,客户端需要将这个token存储起来,每次向服务端发起请求时需要带着这个token,服务端收到请求后,就对这个token进行验证,验证这个token里面包含的是否是当前用户的身份特征,验证成功后,就向客户端返回请求的数据。

   如何将用户的身份特征封装进token里面,以下我用一个rust代码举例,


use chrono::{Duration, Local};
use jsonwebtoken::errors::ErrorKind;
use jsonwebtoken::{decode, encode, DecodingKey, EncodingKey, Header, Validation};
use serde::{Deserialize, Serialize};
use actix_web::error::Error;


/// JWT authentication Token structure
#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)]
pub struct JWTToken {
    pub id: String,
    pub account: String,
    pub role_ids: Vec<String>,
    pub exp: usize
}
impl JWTToken {
    pub fn from_uid(uid: u64) -> Self {
        let local_time = Local::now();
        let new_time = local_time + Duration::minutes(60*24);
        JWTToken {
            id: uid.to_string(),
            account: "".to_string(),
            role_ids: vec![],
            exp: new_time.timestamp_millis() as usize, // 1 days
        }
    }
    /// create token
    /// secret: your secret string
    pub fn create_token(&self, secret: &str) -> Result<String, Error> {
        return match encode(
            &Header::default(),
            self,
            &EncodingKey::from_secret(secret.as_ref()),
        ) {
            Ok(t) => Ok(t),
            Err(_) => Err(Error::from(actix_web::error::ErrorInternalServerError("JWTToken encode fail!"))), // in practice you would return the error
        };
    }
    // verify token invalid
    /// secret: your secret string
    pub fn verify(secret: &str, token: &str) -> Result<JWTToken, Error> {
        let validation = Validation::default();
        return match decode::<JWTToken>(
            &token,
            &DecodingKey::from_secret(secret.as_ref()),
            &validation,
        ) {
            Ok(c) => Ok(c.claims),
            Err(err) => match *err.kind() {
                ErrorKind::InvalidToken => Err(Error::from(actix_web::error::ErrorBadRequest("InvalidToken".to_string()))), // Example on how to handle a specific error
                ErrorKind::InvalidIssuer => Err(Error::from(actix_web::error::ErrorBadRequest("InvalidIssuer".to_string()))), // Example on how to handle a specific error
                _ => Err(Error::from(actix_web::error::ErrorBadRequest("InvalidToken other errors".to_string()))),
            },
        };
    }
}

首先将需要的身份信息封装成一个结构体,再为这个结构体实现生成token的方法,首先我通过from_uid这个函数为这个结构体存入了一个u64类型的数据,然后通过create_token这个函数为这个结构体包含的数据生成一个token,通过verify这个函数我能拿到token里面的全部信息,以下为运行示例,

#[actix_web::main]
async fn main() {
    let token = JWTToken::from_uid(1);
    let secret = "secret";
    let token_str = token.create_token(secret).unwrap();
    println!("token: {}", token_str);
    let token = JWTToken::verify(secret, &token_str).unwrap();
    println!("token: {:?}", token);
}

运行结果如下,


token: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpZCI6IjEiLCJhY2NvdW50IjoiIiwicm9sZV9pZHMiOltdLCJleHAiOjE3MTE4MDEwNjY4MjF9.TdT3YmaTqX0TYZYzESNRgwOuwYqbyuFBxrzNiE-H5cg

token: JWTToken { id: "1", account: "", role_ids:[], exp: 1711801066821 }