这是我以前尝试获取某些信息的内容,但我从未找到问题的实际答案或解决方案。所以希望有人可以澄清并指出我正确的方向。
我已经将问题分成底部的3个问题,所以如果他们可以回答为1,2,3,那就会让事情变得更容易消化,并帮助我解决这个问题。
基本上,我使用CakePHP进行OAuth2服务器设置,以下JavaScript可以与之通信以允许用户登录并获取访问令牌,然后使用此令牌向不同的端点发出各种请求以发送和接收数据。 / p>
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,然后使用HTML5中的localStorage存储。一旦access_token不再起作用,refresh_token用于获取新的access_token,因此用户无需继续登录即可获得无缝体验(除非他们实际注销!)。这是由checkTokenValid
函数处理的,我调用它来检查它是否仍然有效,如果refresh_token不存在,则请求新令牌或让用户再次登录(或者是也无效)。
第一个问题是必须存储refresh_token。这通常不是问题,因为它存储在服务器端,但是因为它的客户端侧是客户端ID,所以如果有人要访问用户浏览器,他们可以请求新的令牌。那么如何在不使用刷新令牌的情况下让用户登录(即自动请求新的access_token)? 这是一个问题,因为它只在用户计算机上出现!
第二个问题是,我被告知我不应该使用这种类型的授权类型(密码/资源所有者密码凭证),因为它是客户端和因此,客户ID和秘密等内容无法得到保护。而我应该使用Implicit。但是,我还没有看到这将如何帮助我解决第一个问题。有人能举例说明吗?以及如何解决上面的refresh_token问题。根据我所读到的有关隐式授权类型的内容,它所做的只是简化令牌流程(通过删除对客户端ID的需要)并且实际上并没有做任何不同的事情。
< / LI>最后,因为应用程序将始终是使用API的唯一应用程序,所以用户无需通过令牌授权类型进程,因此整个客户端ID的设置似乎有点过分。只是一些JavaScript与API交谈。我还有其他选择吗?我已经考虑过要解雇OAuth,而只是选择Basic Auth ......那会话呢?因为我没有令牌!想法?
答案 0 :(得分:3)
没有人强迫您发出刷新令牌,或者在每次请求时使访问令牌失效。如果您发出有效一小时或两小时的访问令牌,那么用户应该有足够的时间使用该网站,而不允许使用“无休止的”#34;刷新链刷新令牌提供(通常使用刷新令牌将导致发出新的访问和刷新令牌)。选择允许典型用户操作期限的有效期,允许一些额外的期限,并且您可以完全避免发布刷新令牌。
当然,用户有可能超过该时间跨度并被迫再次登录。我认为通常如果发生这种情况,如果向他们解释说这是出于安全原因以及简单,非技术性条款发生的事情,那么他们就可以了。最后,它总是在最佳安全性和最佳可用性之间进行权衡:显而易见的是,更好的可用性将使用刷新令牌 - 您的用户在使用页面时将永远不会被迫重新登录 - 但是,如果你这样做,你必须忍受存在被侵害的风险。
本地存储受同一原始策略的保护,因此它与浏览器提供的任何内容一样安全。就个人而言,我喜欢使用会话cookie存储令牌的想法 - 它可以跨浏览器选项卡工作,当浏览器关闭时被清除,当用户手动清除他们的cookie时,他们会得到被遗忘的预期行为。 #34;通过您的页面(他们赢得了浏览器本地/会话存储)。如果您这样做,请确保使用仅安全的cookie。将cookie路径设置为不存在的值将使其不会在每个请求上传输,尽管这纯粹是消息大小的考虑因素,因为它将在每个请求上传输(在Authorization标头中)。无论您使用何种存储类型,您总是容易受到XSS攻击,因此请务必谨慎对待它。
我的观点简而言之:您不需要在每次请求时发出刷新令牌或过期访问令牌。如果您想避免使用刷新令牌,请让您的访问权限更长久 - 但您必须忍受用户在使用您的网站时必须重新进行身份验证的情况。
您不鼓励使用资源所有者密码凭据流的原因通常是因为它强制用户公开其用于您正在使用的其他身份提供商的凭据验证他们。即如果您允许用户使用他们的Google / Facebook登录,则您不应该使用该流程,因为用户必须将您的用户名和密码提供给您的应用/网站,并且您可以执行各种操作与他们一起的恶作剧。
另一方面,从您了解问题的方式开始,您自己的OAuth2服务器已启动并运行,您就拥有了自己的身份提供商 - 您已经拥有对用户的访问权限#39;凭据(用户名和散列密码),因此避免资源所有者流没有额外的安全性好处。 RFC 6749实际上并未指定客户端ID和秘密用于此流程(并且它也没有多大意义),因此,无需保护您不必提供的内容。
我的观点简而言之:因为您是自己的身份提供者,使用资源所有者密码凭据流程是可以的。您不需要客户端ID和/或密码。 Autorization Grant流程和Implicit流程适用于您针对其他身份提供商(例如Google或Facebook)进行身份验证时
可能最常用的身份验证机制仍然是基于会话的,即服务器,当您登录时,会向您发出会话ID,通过该会话ID跟踪您已成功通过身份验证的事实。通常,此会话ID存储为cookie。美妙的是你几乎没有任何实现问题 - 设置cookie,浏览器将为你处理几乎所有细节。在服务器上,您所要做的就是检查会话是否有效。但是,这种机制仍然容易受到XSS攻击,更糟糕的是XSRF(跨站点请求伪造)。虽然不是不可能防范,但检测并防止这种情况发生有点痛苦。使用基于令牌的身份验证系统,您可以获得内置的XSRF保护。
我的观点简而言之:既然您已经启动并运行了OAuth2服务器,我会坚持下去。如果您使用资源所有者密码凭据流,则无需使用客户端ID和密码。
答案 1 :(得分:2)
答案 2 :(得分:0)
为了获得刷新令牌,您需要使用代码流,而不是隐式授权流。
您无法在隐式流程中安全地刷新令牌。
显然,您可以在客户端中实现授权代码流(即 - 就像它是服务器一样),但这会导致2个问题:
1)如果您的IDP(身份提供商)位于您的客户端以外的其他域中,您的浏览器将阻止您进行HTTP调用以从用户生成的代码(或使用refresh_token)生成令牌。
2)您的客户机密将在客户端内部提供 - 这是一个安全漏洞。刷新令牌也将可用 - 另一个安全漏洞。
简而言之 - 无法提供无缝刷新体验&#34;当使用隐式oAuth流时。