如何将 JWT 从客户端传递到我的 API 以进行正确身份验证?

Posted

技术标签:

【中文标题】如何将 JWT 从客户端传递到我的 API 以进行正确身份验证?【英文标题】:How can I pass a JWT from the client side to my API to be properly authenticated? 【发布时间】:2019-09-16 03:26:01 【问题描述】:

我需要将带有 GET、POST、PUT、DELETE 方法的 JWT 从我的 UI 传递到我的 API。

为此,我尝试使用 ReactJS 创建一个前端。我明白了:

POST http://localhost:4000/book/ 401(未经授权) 当我尝试发送请求时。

我知道我必须传递我的令牌,这是我在向 mongo DB 发送数据时通过邮递员完成的。 我是 MERN 堆栈的新手,所以我仍在努力理解。

    这是图书控制器
import mongoose from 'mongoose';
import  book_schema  from '../model/book_model';

const Book = new mongoose.model('Book', book_schema);

export const add_new_book = (req, res) => 
    let new_book = new Book(req.body);

    new_book.save((err, book) => 
        if (err) 
            res.send(err);
        
        res.json(book);
    );
;
    这些是图书路线
import add_new_book from '../controller/book_controller';
import authorization from '../controller/user_controller';

const book_routes = (app) => 

    //GET
    app.route('/book')
        //POST
        .post(authorization,add_new_book);

    这是用户控制器
import mongoose from 'mongoose';
import bycrypt from 'bcrypt';
import jwt from 'jsonwebtoken';

import  user_schema  from '../model/user_model';

const User = mongoose.model('User', user_schema);

export const register = (req, res) => 
    const new_user = new User(req.body);
    new_user.hash_password = bycrypt.hashSync(req.body.password, 10);
    new_user.save((err, user) => 
        if (err) 
            return res.status(400).send(
                message: err
            );
         else 
            user.hash_password = undefined;
            return res.json(user);
        
    );
;

export const authenticate = (req, res) => 
    User.findOne(
        user_name: req.body.user_name
    , (err, user) => 
        if (err) throw err;
        if (!user) 
            res.status(401).json( message: 'Authentication Failed ! - No User.' )
         else if (user) 
            if (!user.comparePassword(req.body.password, user.hash_password)) 
                res.status(401).json( message: 'Authentication Failed ! - Wrong Password.' )

             else 
                var token = res.json(
                    token: jwt.sign( user_name: user.user_name , 'RESTFULAPIs',  expiresIn: '24h' )
                );
                //$window.sessionStorage.accessToken = response.body.access_token;
                return token;
            
        
    );
;

export const authorization = (req, res, next) => 
    if (req.user) 
        next();
     else 
        return res.status(401).json( message: 'Unauthorized User !' )
    
;

export const de_authenticate = (req, res) => 

;
    这是服务器
import express from 'express';
import cors from 'cors';
import bodyParser from 'body-parser';
import mongoose from 'mongoose';
import jsonwebtoken from 'jsonwebtoken';
import db_config from './config_db.js';

const app = express();
const PORT = 4000;

//import routes here
import book_routes from './api/route/book_route';
import user_routes from './api/route/user_route';
import item_routes from './api/route/item_route';


//mongo DB connection
mongoose.Promise = global.Promise;
mongoose.connect(db_config.DB,  useNewUrlParser: true ).then(
    () =>  console.log('Database is connected') ,
    err =>  console.log('Can not connect to the database' + err) 
);

app.use(cors());
app.use(bodyParser.urlencoded( extended: true ));
app.use(bodyParser.json());

//JWT setup
app.use((req, res, next) => 
    if (req.headers && req.headers.authorization && req.headers.authorization.split(' ')[0] === 'JWT') 
        jsonwebtoken.verify(req.headers.authorization.split(''), [1], 'RESTFULAPIs', (err, decode) => 
            if (err) req.user = undefined;
            req.user = decode;
            //console.log(req.user );
            //console.log(decode);
            next();
        );
     else 
        req.user = undefined;
        next();
    
);


//to app
book_routes(app);
user_routes(app);
item_routes(app);


app.get('/', (req, res) =>
    res.send(`Node Server and Express Server Running on Port : $PORT`)
);

app.listen(PORT, function () 
    console.log(`Server is running on Port: $PORT`);
);

我使用 ReactJS 开发前端并导入 axios 以通过 URL 访问 API。在 insert_book.js 文件中,我的表单提交函数是这样的,

  onSubmit(e) 
        e.preventDefault();
        const book_obj = 
            book_no:this.unique_id_generator(),
            isbn_no: this.state.isbn_no,
            author: this.state.author,
            published_year: this.state.published_year,
            publisher: this.state.publisher,
            category:this.state.category
        ;
        axios.post('http://localhost:4000/book/', book_obj)
            .then(res => console.log(res.data));
        this.setState(
            isbn_no: '',
            author:'',
            published_year: '',
            publisher: '',
            category:''
        )
    

最后我想提供用户路线代码,

import register,
    authenticate,
    authorization
 from '../controller/user_controller';

const user_routes = (app) => 

    //SIGNUP
    app.route('/auth/signup')
        //POST A USER
        .post(register);

    //SIGNIN
    app.route('/auth/signin')
    //AUTHENTICATE USER
    .post(authenticate);

export default user_routes;

这是我卡住的地方:

    如何将这些令牌存储在会话中以便与未来的请求一起发送? 如何使用 GET、POST、PUT、DELETE 方法附加和发送令牌值?

【问题讨论】:

使用这个将令牌保存在本地存储res=>localStorage.setItem('token',(res.data.token)) 【参考方案1】:

所以将令牌存储在本地存储中:

const user: User = getUserFromBackend()
// assuming user is an object
localStorage.setItem('token', user.token);
// get token
const token = localStorage.getItem('token');

使用令牌头发出请求:

const token = localStorage.getItem('token');
fetch(url, 
        method: "POST", 
        headers: 
            "Content-Type": "application/json",
            'Authorization': `Bearer $token`,
        ,
        body: JSON.stringify(data), // body data type must match "Content-Type" header
    )
    .then(response => response.json())

【讨论】:

你能帮我实现吗?因为我在处理创建的令牌时遇到了问题。 是的,如果它保存在本地存储而不是 cookie 中,则很容易访问。【参考方案2】:

虽然迟到了。如果可能的话,我建议将 JWT 存储在 cookie 中。然后,您只需读取 cookie 并在需要身份验证的请求的标头中传递 JWT。我更喜欢调用 header 键 x-api-token 并将其值设置为 JWT 字符串。

此外,您只需通过解密此 JWT 并验证,从您的后端对用户进行一次身份验证。验证 JWT 后,您可以为经过身份验证的用户创建会话。此会话将在半小时或您在应用中配置的任何内容后到期。

这样你就不需要再次发送 JWT,因为会话是有效的。我并不是说发送 JWT 不好,有时在您不为经过身份验证的用户创建会话的应用程序中是必需的。执行需要一次性身份验证的操作(如支付处理)时会发生这种情况。

使用 node 的 JWT-decode 包 (https://www.npmjs.com/package/jwt-decode) 实现这个逻辑应该不是问题。

希望这会有所帮助。

【讨论】:

以上是关于如何将 JWT 从客户端传递到我的 API 以进行正确身份验证?的主要内容,如果未能解决你的问题,请参考以下文章

传递 JWT 令牌以访问 API

PHP:如何使用 JWT 从 API 注销

JWT 私钥/公钥混淆

如何证明 JWT 是不是有效并且是不是真的来自 Microsoft?

如何通过 AngularJS 传递 JsonWebToken(JWT)

我如何模拟 auth0 身份验证以进行测试?