我目前正在尝试使用 OAuth2 开发一个完全用 JavaScript 构建的移动应用程序,该应用程序与 CakePHP API 对话。查看以下代码以了解我的应用程序当前的外观 (请注意,这是一个实验,因此代码凌乱,区域缺乏结构等。)
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();
});
});
}(),
checkAuthenticated: function() {
access_token = window.localStorage.getItem('access_token');
if( access_token == null ) {
App.splash();
}
else {
Users.checkTokenValid(access_token);
}
},
checkTokenValid: function(access_token){
$.ajax({
type: 'GET',
url: 'http://domain.com/api/oauth/userinfo',
data: {
access_token: access_token
},
dataType: 'jsonp',
success: function(data) {
console.log('success');
if( data.error ) {
refresh_token = window.localStorage.getItem('refresh_token');
if( refresh_token == null ) {
App.splash();
} else {
Users.refreshToken(refresh_token);
}
} else {
App.home();
}
},
error: function(a,b,c) {
console.log('error');
console.log(a,b,c);
refresh_token = window.localStorage.getItem('refresh_token');
if( refresh_token == null ) {
App.splash();
} else {
Users.refreshToken(refresh_token);
}
}
});
},
refreshToken: function(refreshToken){
$.ajax({
type: 'GET',
url: 'http://domain.com/api/oauth/token',
data: {
grant_type: 'refresh_token',
refresh_token: refreshToken,
client_id: 'NTEzN2FjNzZlYzU4ZGM2'
},
dataType: 'jsonp',
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);
}
});
},
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: 'jsonp',
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);
}
});
},
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();
}
};
我有一些与我的 OAuth 实现相关的问题:
1.) 显然将 access_token 存储在 localStorage 中是不好的做法,我应该改用 cookie。谁能解释为什么?因为据我所知,这不再安全或不那么安全,因为 cookie 数据不会被加密。
更新:根据这个问题:Local Storage vs Cookies无论如何,将数据存储在 localStorage 中仅在客户端可用,并且不执行任何与 cookie 不同的 HTTP 请求,因此对我来说似乎更安全,或者至少据我所知似乎没有任何问题!
2.) 关于问题 1,使用 cookie 作为过期时间,对我来说同样毫无意义,就好像您查看代码一样,在应用程序启动时发出请求以获取用户信息,如果它在服务器端已过期,需要 refresh_token。所以不确定在客户端和服务器上都有到期时间的好处,当服务器才是真正重要的时候。
3.) 如何在没有 A 的情况下获取刷新 token ,将其与原始 access_token 一起存储以备后用,以及 B) 还存储一个 client_id?有人告诉我这是一个安全问题,但我以后如何使用这些,但在仅 JS 的应用程序中保护它们?再次查看上面的代码以了解到目前为止我是如何实现的。
最佳答案
看起来您正在使用 Resource Owner Password Credentials OAuth 2.0 流程,例如提交用户名/通行证以获取访问 token 和刷新 token 。
考虑到这一背景,让我回答您的问题:
http://domain.com/api/oauth/token
,并同时收到 访问 token 和刷新 token . 诚然,这确实违反了您正在寻找的“仅 JS”约束。但是,a) 同样,您真的不应该在 javascript 中使用刷新 token ,并且 b) 它在登录/注销时需要非常少的服务器端逻辑,并且不需要持久的服务器端存储。
关于CSRF的说明 :如评论中所述,此解决方案未解决 Cross-site Request Forgery ;见 OWASP CSRF Prevention Cheat Sheet获取有关解决这些攻击形式的进一步想法。
另一种选择是根本不请求刷新 token (不确定这是否是您正在处理的 OAuth 2 实现的一个选项;刷新 token 是可选的 per the spec )并在它到期时不断重新进行身份验证。
希望有帮助!
关于javascript - 在 HTML5 Web App 中使用 OAuth2,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18280827/