Это то, о чем я пытался получить информацию ранее, но я никогда не нашел ответ или решение проблемы. Поэтому, надеюсь, кто-то может прояснить ситуацию и указать мне в правильном направлении.Использование токенов доступа с JavaScript в OAuth2
Я разделил проблемы на 3 вопроса внизу, так что, если на них можно было ответить как 1,2,3, это значительно облегчило бы переваривание и помогло бы мне разобраться в этом.
В основном, у меня есть установка OAuth2 sever с использованием CakePHP, с которой можно связаться с JavaScript, чтобы позволить пользователю войти в систему и получить токен доступа, а затем сделать различные запросы к разным конечным точкам, используя этот токен для отправки и получения данных.
var access_token,
refresh_token;
var App = {
init: function() {
$(document).ready(function(){
Users.checkAuthenticated();
});
}(),
splash: function() {
var contentLogin = '<input id="Username" type="text"> <input id="Password" type="password"> <button id="login">Log in</button>';
$('#app').html(contentLogin);
},
home: function() {
var contentHome = '<h1>Welcome</h1> <a id="logout">Log out</a>';
$('#app').html(contentHome);
}
};
var Users = {
init: function(){
$(document).ready(function() {
$('#login').live('click', function(e){
e.preventDefault();
Users.login();
});
$('#logout').live('click', function(e){
e.preventDefault();
Users.logout();
});
});
}(),
// Check that if user is logged in (has an access token)
checkAuthenticated: function() {
access_token = window.localStorage.getItem('access_token');
if(access_token == null) {
Users.logout();
}
else {
Users.checkTokenValid(access_token);
}
},
// Check the token is still valid on the server for access (also get User info)
checkTokenValid: function(access_token){
$.ajax({
type: 'GET',
url: 'http://domain.com/api/oauth/userinfo',
data: {
access_token: access_token
},
dataType: 'json',
success: function(data) {
console.log('success');
console.log(data);
if(data.error) {
refresh_token = window.localStorage.getItem('refresh_token');
if(refresh_token == null) {
Users.logout();
} else {
Users.refreshToken(refresh_token);
}
} else {
App.home();
}
},
error: function(a,b,c) {
console.log('error');
console.log(a);
refresh_token = window.localStorage.getItem('refresh_token');
if(refresh_token == null) {
Users.logout();
} else {
Users.refreshToken(refresh_token);
}
}
});
},
// Request a new access token using the refresh token
refreshToken: function(refresh_token){
$.ajax({
type: 'GET',
url: 'http://domain.com/api/oauth/token',
data: {
grant_type: 'refresh_token',
refresh_token: refresh_token,
client_id: 'NTEzN2FjNzZlYzU4ZGM2'
},
dataType: 'json',
success: function(data) {
if(data.error) {
alert(data.error);
} else {
window.localStorage.setItem('access_token', data.access_token);
window.localStorage.setItem('refresh_token', data.refresh_token);
access_token = window.localStorage.getItem('access_token');
refresh_token = window.localStorage.getItem('refresh_token');
App.home();
}
},
error: function(a,b,c) {
console.log(a,b,c);
Users.logout();
}
});
},
// send login credentials and store tokens in localStorage and in variables
login: function() {
$.ajax({
type: 'GET',
url: 'http://domain.com/api/oauth/token',
data: {
grant_type: 'password',
username: $('#Username').val(),
password: $('#Password').val(),
client_id: 'NTEzN2FjNzZlYzU4ZGM2'
},
dataType: 'json',
success: function(data) {
if(data.error) {
alert(data.error);
} else {
window.localStorage.setItem('access_token', data.access_token);
window.localStorage.setItem('refresh_token', data.refresh_token);
access_token = window.localStorage.getItem('access_token');
refresh_token = window.localStorage.getItem('refresh_token');
App.home();
}
},
error: function(a,b,c) {
console.log(a,b,c);
}
});
},
// Clear the localStorage and token variables and load the login (splash page)
logout: function() {
localStorage.removeItem('access_token');
localStorage.removeItem('refresh_token');
access_token = window.localStorage.getItem('access_token');
refresh_token = window.localStorage.getItem('refresh_token');
App.splash();
}
};
Надеется, что код все это имеет смысл ... но в двух словах, он посылает имя пользователя и пароль к API, который затем посылает обратно как в access_token и refresh_token, что я тогда магазин используя LocalStorage в HTML5. Refresh_token используется для получения нового access_token после того, как access_token больше не работает, поэтому пользователь получает беспрепятственный опыт без необходимости вести вход в систему (если только они не выходят из системы!). Это обрабатывается функцией checkTokenValid
, которую я вызываю, чтобы проверить, что она по-прежнему действительна, и либо запросить новый токен, либо сделать запрос пользователя повторно, если refresh_token не существует (или также недействителен).
Первой проблемой является сохранение refresh_token. Это, как правило, не будет проблемой, поскольку оно будет храниться на стороне сервера, но поскольку на клиентской стороне отображается идентификатор клиента, и поэтому, если кто-то должен был получить доступ к браузеру пользователей, они могут запрашивать новые токены. Итак, как я могу заставить пользователя войти в систему (т. Е. Запросить новый access_token автоматически) без использования токенов обновления? Это даже проблема, поскольку это только на машине пользователя!
Вторая проблема: мне сказали, что я не должен использовать этот тип типа гранта (пароль/пароль владельца ресурса), потому что это клиентская сторона и, следовательно, такие вещи, как идентификатор клиента, и секрет не может быть защищен. И вместо этого я должен использовать Implicit. Однако я не смог понять, как это поможет мне решить первую проблему. Может ли кто-нибудь показать пример этого? И как это решит проблему refresh_token выше. Из того, что я прочитал относительно неявного типа гранта, все, что он делает, просто упрощает процесс маркера (устраняя необходимость в идентификаторе клиента) и фактически не делает ничего другого.
Наконец, поскольку приложение ВСЕГДА будет единственным приложением, использующим API, пользователю не нужно будет когда-либо проходить через процесс предоставления типа токена, поэтому вся настройка идентификаторов клиентов кажется излишним для того, что просто некоторые JavaScript говорят с API. Какие у меня есть другие варианты? Я думал о том, чтобы уволить OAuth и просто пойти с Basic Auth вместо этого ... Но как насчет сеансов? Так как у меня не будет токена! Мысли?
+1. Я пытался получить ответ на этот вопрос (предлагал щедрость), но без большой удачи. Наилучшие ответы можно найти на страницах, опубликованных здесь, которые просто подтверждают, что, когда вы находитесь в SPA с неявным потоком, нет хорошего варианта для сохранения токена на клиенте. Из двух, которые я видел, реализовано, есть один, содержащий только cookie http для хранения токена обновления, и тот, который предлагает Taiseer, использует CORS. Очень жаль, что в SPA не публикуется больше о том, как справиться с этим. – Tom