简体   繁体   中英

Cannot overgive the user parameter to req.user in jwt.verify function

I am currently writing a jwtVerify.ts. It is the first time I am using TypeScript. Vs-code underlines the req.user and tells me that error:

The type "undefined" cannot be assigned to the type object".ts(2322).

I tried now to check it like this:

if(user !== undefined){
           req.user = user;
            }

But then it tells me:

The type string cannot be assigned to type "my user object" (2322).

I tried in my index.d.ts to define user with any, but then I have errors in all jwt functions. I tried to define user in the function as object but that gives back:

No overload matches this call.

The code is the following:

import * as jwt from 'jsonwebtoken'
import { Request, Response, NextFunction } from 'express';
export const verifyToken = (req:Request, res:Response, next:NextFunction)=>{
    const sec:string = process.env.JWT_SEC as string;
    const authHeader = req.headers.token;
    if(authHeader){
        const token = (authHeader as string).split(' ')[1];
        jwt.verify(token, sec, (err, user)=>{
            if(err){
                res.status(403).json('Token is not valid');
            }
           req.user = user;
            next();
        })
    } else{
        return res.status(401).json('You are not authorized');
    }
};

I have a @types folder with a file index.d.ts, in which I globally define an interface for Request user:

declare global {
    namespace Express {
        interface Request {
            user:{
                id:string!;
                vorname:string!;
                nachname:string!;
                username:string!;
                email:string!;
                street:string!;
                number:string!;
                plz:number!;
                city:string!;
                password:string!;
                isAdmin:boolean!;
                createdAt: Date!;
                updatedAt: Date!;
            }
        }
    }
}

The Request interface works. When I hover the "user" of req.user then vs-code shows me the content. When I hover the user parameter in my function, vs-code tells me, that it is "string | jwt.JwtPayload | undefined". So how I can define user in a way that TypeScript accepts this value? Without typeScript this function works. I used it before in my Mern-Stack exam.

I add my model, perhaps here is something wrong:

import mongoose from 'mongoose';

export interface UserDocument extends mongoose.Document{
    vorname:string;
    nachname:string;
    username:string;
    email:string;
    street:string;
    number:string;
    plz:number;
    city:string;
    password:string;
    isAdmin:boolean;
    createdAt: Date;
    updatedAt: Date;
    _doc?: any;
  }
const UserSchema = new mongoose.Schema<UserDocument>({
    vorname:{type:String, required:true},
    nachname:{type:String, required:true},
    username:{type:String, required:true },
    email:{type:String, required:true },
    street:{type:String, required:true },
    number:{type:String, required:true },
    plz:{type:Number, required:true },
    city:{type:String, required:true },
    password:{type:String, required:true },
    isAdmin:{type:Boolean, default:false},
}, 
    {timestamps:true}
)

const User = mongoose.model<UserDocument>('User', UserSchema);

export default User;

I don't have id in the model because Mongo sets it automatically. I have _doc in the interface, because of the following function:

let sec:string = process.env.JWT_SEC as string;

const accessToken = jwt.sign(
            {id: user!._id,
             isAdmin:user!.isAdmin,
            },
            sec,
            {expiresIn:"30d"}
        )
        const {password, ...others} = user?._doc;
        response.status(200).json({...others, accessToken});

Without _doc in the interface, it throws me an error.

You need to create global.d.ts file to explicitly add typing in any object.

Create global.d.ts file in the root directory. Write the following code in this file.

import 'express-serve-static-core'
    
export interface User {
  id:string!;
  vorname:string!;
  nachname:string!;
  username:string!;
  email:string!;
  street:string!;
  number:string!;
  plz:number!;
  city:string!;
  password:string!;
  isAdmin:boolean!;
  createdAt: Date!;
  updatedAt: Date!;
}

declare module 'express' {
  export interface Request {
    user?: User
  }
}

In tsconfig.json file do this

{
   "compilerOptions": {
     // Other options
     "typeRoots": ["./node_modules/@types"]
   },
   "include": ["./**/*.ts"],
   files: ["global.d.ts"]
}

Find the user using Mongoose Model then save it in req.user object. In your jwtVerify.ts do this

import * as jwt from 'jsonwebtoken'
import { User } from 'usermodelpath'
import { Request, Response, NextFunction } from 'express';

export const verifyToken = (req:Request, res:Response, next:NextFunction)=>{
    const sec:string = process.env.JWT_SEC as string;
    const authHeader = req.headers.token;
    if(authHeader){
        const token = (authHeader as string).split(' ')[1];
        jwt.verify(token, sec, async (err, decoded)=>{
            if(err){
                res.status(403).json('Token is not valid');
            }
           const user = await User.findOne({_id: decoded.id}).lean()
           if(!user) return res.status(400).json({error: 'Not Authorised!' })
           
           req.user = user;
           next();
        })
    } else{
        return res.status(401).json('You are not authorized');
    }
};

Okay, finally I have written some code that works. Thanks to Neeray Kumar, his answer helped. Thats the code:

export interface UserDocument extends mongoose.Document{
    vorname:string;
    nachname:string;
    username:string;
    email:string;
    street:string;
    number:string;
    plz:number;
    city:string;
    password:string;
    isAdmin:boolean;
    createdAt: Date;
    updatedAt: Date;
    _doc?: any;
    organization: Types.ObjectId; //This I found in the mongoose documentation. 
  }
const UserSchema = new mongoose.Schema<UserDocument>({
    vorname:{type:String, required:true},
    nachname:{type:String, required:true},
    username:{type:String, required:true },
    email:{type:String, required:true },
    street:{type:String, required:true },
    number:{type:String, required:true },
    plz:{type:Number, required:true },
    city:{type:String, required:true },
    password:{type:String, required:true },
    isAdmin:{type:Boolean, default:false},
    organization: { type: mongoose.Schema.Types.ObjectId, ref: 'Organization' } //organization out of mongoose documentation
}, 
    {timestamps:true}
)

And that is the jwt.verify:

export const verifyToken = (req:Request, res:Response, next:NextFunction)=>{
    const sec:string = process.env.JWT_SEC as string;
    const authHeader = req.headers.token;
    console.log(authHeader);
    if(authHeader){
        const token = (authHeader as string).split(' ')[1];
        jwt.verify(token, sec, async (err, user)=>{
            if(err){
                res.status(403).json('Token not valid');
            }
            if(!user) return res.status(400).json({error:"Not authorized"})
            console.log(user, req.user);
            if(user){
               req.user = <any>user; //that is the way to overgive user
            }
            next();
        })
    } else{
        return res.status(401).json('Not authorized');
    }
};

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM