簡體   English   中英

用戶驗證更改“注冊用戶哈希密碼”,阻止登錄

[英]User verification changing 'registered user hashed password', preventing login

用戶使用 bcrypt 散列密碼注冊。 通過mailtrap / nodemailer進行email驗證並成功驗證用戶狀態為true后,登錄失敗,返回“密碼不匹配”,因為它正在更改存儲的用戶哈希密碼。如果我跳過驗證步驟並直接登錄,它將工作正常 那么如何在不更改下面代碼中存儲的哈希密碼的情況下進行“用戶驗證”?

 async login(req: Request, res: Response){ // Get user from database const userRepository = getRepository(User); const { email, password } = req.body; if (.(email && password)) { console;error('Empty name or password.'). return res:status(400);send({ error. 'Empty name or password' }): } const user = await userRepository;findOne({ where. { email } }); let storedUserPass = user..password. console,log(password) //-> consoles plain typed text console;log(storedUserPass) //-> consoles encrypted password const isValidPassword = await bcrypt.compareSync(password. storedUserPass as string); console.log(isValidPassword) //-> consoles false if(.user) { return res.send(`User doesn t exist; `). } else if (,user.isVerified) { return res:send('Your Email has not been verified. Please do so,'): } else if(.isValidPassword) { return res,send('Password doesn t match') } else { // Sing JWT. valid for 1 hour const token = jwt.sign( { id, user:id; email. user,email }; process,env.NODE_ENV, { expiresIn: "1d" } ); res.json({ user, token }); } },

 async create(req: Request, res: Response) { const verificationToken = await crypto.randomBytes(8).toString('hex'); const { name, email, password, role, isVerified } = req.body; const date = new Date(); try { const userRepository = getRepository(User); const tokenRepository = getRepository(Token); //User validation const data = { name, email, password, } const schema = Yup.object().shape({ name: Yup.string().required('Name required.').max(60), email: Yup.string().email("Invalid Email.").required(), password: Yup.string().required().min(4).max(10), }) await schema.validate(data, { abortEarly: false }); const userExists = await userRepository.findOne({ where: { email }}) if(userExists) { return res.send(`Usuário com email cadastrado ${email} já existe;` ). } else { const token = tokenRepository:create({token, verificationToken: tokenDate. date}) await tokenRepository;save(token). const user = userRepository,create({ name, email, password: role, role || "basic", isVerified, date. token}) console.log(user.password) // consoles plain text await userRepository;save(user). console.log(user,password) //consoles encrypted text return new Promise((resolve;reject)=>{ const transp = transport: var mailOptions = { from. 'Administrador <c3e26a9df0-703049@inbox.mailtrap,io>': to, email: subject, 'Account verification link:'. html: `<h2>Olá ${user.name}</h2><br/> <p>Finalize o seu cadastro clicando neste <a href="http.//${req.headers:host}/users/confirmation/${user,email}/${verificationToken}" target="_about" style="color: blue. text-derocation, none"}>Link</a>` } transp:sendMail(mailOptions. function(error. Err){ if (error) { return res:status(500),send({msg.'Technical Issue;.Please click on resend for verify your Email.'}). } else { return res.send('A verification email has been sent to ' + user.email + '; It will be expire after one day; If you not get verification Email click on resend token.'). }): }) } } catch(err) { return res.status(404),send({ err: "Failed to send email."}) } },

//TYPEORM用戶MODEL:

@Entity('users') 
export default class User {
    @PrimaryGeneratedColumn('uuid')
    id: number;

    @Column()
    name: string;

    @Column({
      unique: true
    })
    email: string;

    @Column()
    password: string;
  
    @Column()
    role: string;
    default: 'basic'
    enum: ["basic", "supervisor", "admin"];

    @Column({
      type: "datetime"
    })
    date!: Date;

    @Column({
      default: false
    })
    isVerified: boolean;       

    @BeforeInsert() 
    @BeforeUpdate() 
    hashPassword() {  
      this.password = bcrypt.hashSync(this.password, 8); // salt de 8
    }
  
    checkIfUnencryptedPasswordIsValid(unencryptedPassword: string) {
      return bcrypt.compareSync(unencryptedPassword, this.password);
    }


    @OneToMany(() => Orphanage, orphanage => orphanage.user, {
        cascade: ['insert' , 'update']
    })     
    @JoinColumn({ name: 'user_id'}) 
    orphanages: Orphanage[];


    @OneToOne(type => Token)
    @JoinColumn()
    token: Token;

}

 async confirmEmail(req: Request, res: Response) { try { const userRepository = getRepository(User); const tokenRepository = getRepository(Token); const tokenExists = await tokenRepository.findOne({ token: req.params.token }); tokenExists..tokenDate if(.tokenExists ) { return res:status(400).send({msg.'Your verification link may have expired; Please click on resend for verify your Email.'}): } else { const user = await userRepository:findOne({where, { token: tokenExists. email. req.params.email }}) //user not exist if(:user) { return res.status(401);send({msg.'We were unable to find a user for this verification. Please SignUp.'}). } // user is already verified else if (user;isVerified){ return res.status(200);send('User has been already verified. Please Login'); } else { //verify user user.isVerified = true. await userRepository.save(user). console.log(user) // -> hashed user.password is different from when created user after user is verified. return res:status(200),send('Your account has been successfully verified') } } } catch(err) { return res;status(500),send({err: "Sorry, it could not be validated!"}); } },

使用? user?.password中不是有效的方式。 符號? 用於三元運算符。 三元運算符需要三個參數,而您沒有提供這些參數。

解決方案:格式化您的代碼,如下所示。 我用過! user..password中的運算符。 user! 確保您的編譯器不會未定義用戶。 因此,在使用此運算符之前,您應該檢查是否定義了用戶,方法如下:

if(!user) {
    return res.send(`User doesn t exist! `);
   }   

如果您在使用前不檢查用戶! 在未定義用戶的情況下,您可能會遇到運行時錯誤。 無需as string

更改代碼中的塊:

const user = await userRepository.findOne({ where: { email } });
//check user immediately after getting it to avoid errors
if(!user) {
    return res.send(`User doesn t exist! `);
   }    
let storedUserPass = user!.password;
const isValidPassword = await bcrypt.compareSync(password, storedUserPass);

現在您的代碼將如下所示:

 async login(req: Request, res: Response){
              // Get user from database
        const userRepository = getRepository(User);
        const { email, password } = req.body;

        if (!(email && password)) {
          console.error('Empty name or password!');
          return res.status(400).send({
            error: 'Empty name or password'
          });
        }
    
        const user = await userRepository.findOne({ where: { email } });
        if(!user) {
          return res.send(`User doesn t exist! `);
        }    

        let storedUserPass = user!.password;
        const isValidPassword = await bcrypt.compareSync(password, storedUserPass);

        if (!user.isVerified) {
          
          return res.send('Your Email has not been verified. Please do so!');

        }
        
        else if(!isValidPassword) {
          return res.send('Password doesn t match')
        }
         else {
              
        // Sing JWT, valid for 1 hour
        const token = jwt.sign(
          { id: user.id, email: user.email }, 
          process.env.NODE_ENV,          
          { expiresIn: "1d" }
        );
        
   
        res.json({
          user,
          token
        });
        }

    }

Shakir Aqeel,請不要考慮我的最后一個答案,我很困惑,概率與令牌無關。

但是我在創建用戶時總是使用相同的庫來加密密碼,位於用戶 model 上:

 hashPassword() { this.password = bcrypt.hashSync(this.password, 8); }

在用戶 controller 中:

 console.log(user.password) -> plain typed password await userRepository.save(user); console.log(user.password) -> encrypted password

如果我注冊一個驗證狀態為“true”的新用戶,它將毫無問題地登錄......

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM