【发布时间】:2019-12-28 20:50:44
【问题描述】:
我正在开发这个由两部分组成的应用程序(React + Express... + Apollo(用于 GraphQL))。 为了管理身份验证,我一直在阅读指南和观看视频,并使用JWT token 和Context API 取得了一些进展,例如:
- 每当用户登录时,React 都会使用 gql(由 apollo-boost 提供支持)向 Express 发出请求。
- Express 服务器(后端)向其发送响应,然后使用解析器处理其数据:
require('dotenv').config();
import { User } from '../models/User';
import bcrypt from 'bcrypt';
import jwt from 'jsonwebtoken';
export default {
Query: {
login: async (_, { email, password }, {req}) => {
try {
const user = await User.findOne({ email });
if (!user) {
throw new Error('User don\'t exist');
}
const isEqual = await bcrypt.compare(password, user.password);
if (!isEqual) {
throw new Error('Wrong credentials');
}
const {
JWTSECRET = 'secret'
} = process.env;
const token = jwt.sign({ userId: user.id, email: user.email }, JWTSECRET, {
expiresIn: '1h'
});
return {
userId: user.id,
token,
tokenExpiration: 3600000 // Date.now()+3600000 doesn't work cause Int is 32-bit signed
}
} catch (e) {
throw new Error(e.message);
}
}
}
};
const hashPassword = async password => {
const saltRounds = 10;
const hashedPassword = await new Promise((resolve, reject) => {
try {
bcrypt.hash(password, saltRounds, (err, hash) => {
if (err) reject(err);
resolve(hash);
});
} catch (e) {
throw new Error(e.message);
}
});
return hashedPassword;
};
- React 获取响应并将其附加到上下文中,我猜它还会分配一些
localStorage的东西来保持会话,例如:
import React from 'react';
import AuthContext from './auth-context';
import ApolloClient, { gql } from 'apollo-boost';
function getClient() {
return new ApolloClient({ uri: 'http://localhost:4000/ws', credentials: 'same-origin' });
}
const AuthState = props => {
const defaultValue = {
userId: null,
userFirstName: null,
userLastName: null,
userEmail: null,
token: null,
tokenExpiration: null,
createdOn: null,
errors: [],
login,
get,
};
return (
<AuthContext.Provider value={defaultValue}>
{props.children}
</AuthContext.Provider>
);
/**
* Login
* @param {string} email
* @param {string} password
*/
async function login(email, password) {
const client = getClient();
const CHECK_CREDENTIALS = gql`
query {
login(email: "${email}", password: "${password}") {
userId
token
tokenExpiration
}
}
`;
const { data, loading, errors } = await client.query({
query: CHECK_CREDENTIALS,
errorPolicy: 'all'
});
if (loading) {
defaultValue.message = "Validating credentials";
}
if (errors) {
defaultValue.errors = errors.map(error => <p>{error.message}</p>);
}
if (data && data.login) {
defaultValue.userId = data.login.userId;
defaultValue.token = data.login.token;
defaultValue.tokenExpiration = data.login.tokenExpiration;
// Persist session ?
localStorage.setItem('user-token', data.login.token);
localStorage.setItem('user-token-expiration', data.login.tokenExpiration);
}
}
async function get(userId) {
const client = getClient();
const GET_USER = gql`
query {
user(_id: "${userId}") {
firstName
lastName
email
}
}
`;
const { data, loading, errors } = await client.query({
query: GET_USER,
errorPolicy: 'all'
});
if (loading) {
defaultValue.message = "Getting user";
}
if (errors) {
defaultValue.errors = errors.map(error => <p>{error.message}</p>);
}
if (data && data.user) {
defaultValue.userFirstName = data.user.firstName;
defaultValue.userLastName = data.user.lastName;
defaultValue.userEmail = data.user.email;
}
}
}
export default AuthState;
- 在每个需要身份验证的组件中,我都会检查
context.token和context.tokenExpiration并重定向到登录或让它们通过。
我一直想知道如果我使用开发者控制台手动设置一些user-token 和user-token-expiration 会怎样?我错过了什么?
感谢任何cmets。
【问题讨论】:
-
你的代码有效吗?
-
@Peter,我还没有尝试使用
localStorage管理,但如果不使用它,它会在我重新加载页面之前工作。
标签: javascript node.js reactjs express jwt