#javascript #node.js #reactjs #oauth
#javascript #node.js #reactjs #oauth
Вопрос:
Я добавляю OAuth в свое клиентское приложение github. У меня успешно возвращен окончательный токен аутентификации, но я чувствую, что взломал свой рабочий процесс.
Текущий поток архитектуры:
1) Пользователь нажимает href
ссылку из компонента, чтобы перейти к начальному маршруту OAUTH
2) Извлеките токен из Github для идентификации пользователя
3) Github перенаправляет на мой серверный маршрут, а мой серверный маршрут отправляет дополнительный запрос POST
на /access_token
страницу запроса с client_secret
, id
и code
с приведенного выше шага.
4) Наконец, я перенаправляю с вышеуказанного маршрута обратно в свой пользовательский интерфейс и устанавливаю параметр URL в процессе
5) В componentDidMount
я удаляю конечный токен аутентификации из window.url
и устанавливаю его в моем состоянии
Примечание: Я планирую сохранить токен в Redux позже, но это базовый уровень того, что я делаю.
Фактический код
Сервер
app.get("/login", async (req, res) => {
// Get the identity token from GitHub origin
return await axios
.post("https://github.com/login/oauth/access_token", {
code: req.query.code,
client_id: process.env.CLIENT_ID,
client_secret: process.env.CLIENT_SECRET
})
.then(async resp => {
// Little hack to parse out the query params into an object
let data = await url.parse("http://parse.com?" resp.data, {
parseQueryString: true
}).query;
res.redirect(
url.format({
pathname: Environment.getUrl(),
query: {
token: data.access_token
}
})
);
});
});
Компонент аутентификации пользовательского интерфейса
export default class GithubAuthentication extends React.Component {
state = {
authToken: "DATA"
};
componentDidMount() {
let currUrl = window.location.href;
this.setState({ authToken: currUrl.split("token=")[1] });
}
render() {
return (
<React.Fragment>
<a href="https://github.com/login/oauth/authorize?client_id=b5cd37110eb31620aad7">
{this.state.authToken ? "Logout" : "Login With Github"}
</a>
<span>{this.state.authToken}</span>
</React.Fragment>
);
}
}
Вопросы
1) Единственное, чего я не смог понять, это сделать href
ссылку контролируемым компонентом и фактически ввести URL-адрес аутентификации чем-то вроде SuperAgent
или Axios
. Вместо этого я вынужден использовать эту href
ссылку, не уверен почему.
2) Действительно ли это разумный способ получения конечного токена аутентификации?
Ответ №1:
Что касается вопроса 2, с точки зрения безопасности, лучше хранить токен доступа на стороне сервера и никогда не отправлять токен на сторону клиента.
Я не смог найти хороших письменных ресурсов, поэтому я хотел бы поделиться этим видео, в котором кратко описывается, как обращаться с токеном доступа.
Отрывок из видео
- У нас все еще нет хорошего способа безопасного хранения токена в браузере
- Сохраняя токен доступа на стороне сервера и используя сессионный файл cookie, вы можете свести к минимуму риск компрометации токена доступа.
Чтобы фактически реализовать этот поток, вы можете использовать cookie-session для генерации сеанса. Вы также можете использовать github-passport для упрощения реализации.
https://github.com/expressjs/cookie-session
https://github.com/jaredhanson/passport-github
Ответ №2:
1) Я думаю, вам следует реорганизовать свое приложение, чтобы вы могли использовать компонент вместо ссылки href. Вы бы узнали, аутентифицированы вы или нет, основываясь на значении свойства state. Это значение может быть передано в качестве prop вашему компоненту, в который вы бы поместили логику аутентификации? «Logout»: «Войти» или что-нибудь еще.
2) поток в порядке, но вы должны убедиться, что выполняете проверку токена на стороне сервера, поскольку легко просто щелкнуть переключателем в пользовательском интерфейсе и очень легко притвориться, что вы аутентифицированы.
Комментарии:
1. Я получал проблемы с перекрестным источником при использовании компонента вместо href. Не совсем уверен, почему это происходит.
2. Проблема CORS возникает, если вы выполняете вызов js на другой сервер, и этот сервер не разрешает нежелательные вызовы из неизвестного приложения, которое включено по умолчанию, поэтому ваш сервер должен разрешать запросы из вашего клиентского домена в
Access-Control-Allow-Origin
заголовке