Реализованы безопасные маршруты JWT - PullRequest
0 голосов
/ 14 января 2020

Я добавляю аутентификацию JWT в приложение блога, над которым работаю. На стороне сервера (построено с Nodejs) я создаю токен и отправляю его обратно с успешным входом в систему. На стороне клиента я сохраняю токен в LocalStorage. Когда я захожу и проверяю вкладку приложения в dev tools, я вижу токен. На маршруте сервера, где размещены блоги, я проверяю аутентификацию. Если токен аутентифицирован, блог публикует в базе данных, но если я удаляю токен или меняю его, а затем отправляю запрос на публикацию, запрос не выполняется, как и ожидалось.

Пока все хорошо.

Что меня смущает, так это то, как ограничить доступ к странице, где редактор блогов находится на клиенте. Если люди не аутентифицированы, они вообще не смогут получить доступ к этой странице, даже если они не аутентифицированы, они не могут публиковать сообщения.

Маршрут входа на сервер:

router.post('/login', async (req, res, next) => {
    const cursor = User.collection.find({username: req.body.username}, {username: 1, _id: 1, password: 1});
    if(!(await cursor.hasNext())) {
        return res.status(401).json({ message: 'Cannot find user with that username' });
    }
    const user = await cursor.next();
    try {
    if(await bcrypt.compare(req.body.password, user.password)) {
        const token = jwt.sign({
            email: user.email,
            userId: user._id
        }, process.env.JWT_SECRET, { expiresIn: "1h" })
        return res.status(201).json({
            message: 'User Authenticated',
            token: token
        });
    } else {
        return res.status(400).json({ 
            authenticated: false,
            username: req.body.username,
            password: req.body.password
        })
    }
    } catch (err) {
        return res.status(500).json({ message: err })
    }
});

Как я проверяю аутентификацию токена на сервере:

const jwt = require('jsonwebtoken');

module.exports = (req, res, next) => {
    try {
        const token = req.headers.authorization;
        console.log(token);
        const decoded = jwt.verify(token, process.env.JWT_SECRET);
        req.userData = decoded;
        next();
    } catch (error) {
        return res.status(401).json({ message: 'Auth Failed' })
    }

}

Мой маршрут входа в систему на стороне клиента:

handleSubmit(event) {
        event.preventDefault();
        const formData = {
            username: event.target.username.value,
            password: event.target.password.value
        }
        fetch('http://localhost:4000/user/login', {
            method: "POST",
            mode: "cors",
            body: JSON.stringify(formData),
            headers: {
                "Content-Type": "application/json"
            }
        })
        .then(res => res.json())
        .then(res => {
            localStorage.setItem('authorization', res.token);
            console.log(res);
        })
        .catch(err => console.error(err)) 
    }

А вот мой запрос на выборку от клиента при публикации в блоге маршрут, в котором находится редактор:

handleSubmit = (event) => {
      event.preventDefault();
      const data = new FormData(event.target);
      const body = event.target.postBody.value;
      const postTitle = event.target.title.value;

      console.log(event.target);
      console.log(data);
      console.log(event.target.postBody.value);

      fetch('http://localhost:4000/blog', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          "Authorization": localStorage.getItem('authorization')
        },
        mode: 'cors',
        body: JSON.stringify({
          title: postTitle,
          postBody: body
        })
      })
      .then(res => res.json())
      .then(err => console.error(err))
    }

Итак, как я уже сказал, все работает, как и ожидалось, но я не хочу, чтобы люди могли получить доступ к странице редактора, если они не аутентифицированы. Я думаю, я бы проверил, существует ли токен в локальном хранилище, а затем перенаправил? Но разве мне не нужно проверять, можно ли аутентифицировать токен на клиенте на сервере? Так нужно ли мне отправлять сообщения на сервер, чтобы выполнять проверку всякий раз, когда кто-то переходит на эту страницу или на любую другую страницу, доступ к которой я хочу ограничить? Если подумать, если пользователь уже аутентифицирован, я не хочу, чтобы он также мог получить доступ к странице входа.

Я слышал, что люди используют Redux для управления состоянием между компонентами, но я действительно я не хочу go идти по этому пути, по крайней мере пока, потому что этот проект предназначен для целей обучения, и я действительно не хочу начинать с Redux или чего-то подобного, пока у меня не получится лучше Gr asp от React по своему усмотрению. Я не знаю, нужен ли мне Redux или нет, и из того, что я понимаю, этого достаточно, чтобы понять, что он мне, вероятно, не нужен.

Это просто такой другой поток, к которому я привык PHP сеансов, и у меня возникли некоторые проблемы, когда я оборачиваюсь вокруг него.

Я понимаю, что вам, ребята, действительно не нужно видеть весь этот код, но я также хотел бы, чтобы некоторые более опытные глаза увидели его и укажите, где бы я ни делал ошибки, или где я мог бы здесь улучшить.

1 Ответ

0 голосов
/ 18 января 2020

Итак, это то, что я придумал на данный момент, если кто-то знает лучший способ, я определенно открыт для предложений.

Я создал класс с именем CheckAuth, который по сути просто делает запрос GET для сервер и отправляет JWT вместе с ним.

checkAuth. js:

class CheckAuth {
    constructor() {
        this.auth = false;
    }

    async checkLogin() {
        console.log(localStorage.getItem("authorization"));
        let data = await fetch('http://localhost:4000/auth', {
            method: "GET",
            mode: "cors",
            headers: {
                "Content-Type": "application/json",
                "authorization": localStorage.getItem("authorization")
            }
        })
        return data.json();

    }

    logout(cb) {
        localStorage.removeItem('authenticated')
        this.auth = false;
        cb();
    }

    async isAuthenticated() {
        const data = await this.checkLogin()
        return data;
    }

}

export default new CheckAuth();

Тогда на страницах, которые только вошли в систему пользователи должны видеть, что я делаю простая проверка, чтобы увидеть, есть ли у них токен и действителен ли он внутри componentDidMount().

componentDidMount() {
        const check = checkAuth.isAuthenticated();
        console.log(check);
        check.then(res => {
            console.log(res);
            if(res.authenticated !== true) {
                this.props.history.push("/login");
            }
        })
        .catch(err => { console.error(err) })
    }
...