我正在为我正在开发的应用程序实施基于OAuth 2的授权模型。我为最终用户提供了使用Facebook登录或使用我的API设置电子邮件/密码帐户的能力。使用密码授权,电子邮件/密码验证很简单。我正在寻找Facebook登录流程的帮助。
我的应用程序是一个单页面应用程序,它使用JSON API(我的资源服务器")。我使用Facebook JavaScript SDK授权网络应用访问最终用户的电子邮件地址。
当用户尝试使用Facebook登录时,整个过程将在Facebook和Web应用程序之间进行。因此,我的API无法信任Facebook授权令牌,直到它使用Facebook的OAuth服务器验证令牌。
截至目前,我已将Facebook accessToken
传递给我的API,然后API通过服务器到服务器调用"来验证用户对Facebook的授权。我"图API。以下是我当前设置的说明:
所以,此时,我有一个Facebook访问令牌和一个电子邮件地址。我需要在我的API服务器和Web应用程序之间保持会话。此时持久化会议的标准方法是什么?
从阅读OAuth文档来看,似乎这种情况需要一个"隐式授权"在我的API服务器和Web应用程序之间,但OAuth package I'm using中没有该授权类型。也是包says implicit grants are "very insecure"。
的作者我的另一个想法是我可以创建随机客户端ID和客户端密钥,然后将它们传递回Web应用程序,以便它可以通过凭据授权请求访问令牌。这对我来说似乎不合逻辑。为什么我不创建访问令牌并将其发送回客户端直接使用?
我应该在Facebook初次授权后直接在我的网络应用和API服务器之间维护身份验证,这是正确的吗?
我意识到我可以生成一个随机密码并向用户发送一个HTTP Basic令牌,但除非没有任何好处,否则我更喜欢使用OAuth。
答案 0 :(得分:2)
我们正在完成您在DynamicApis.com上所讨论的内容。
以下是我们正在做的事情:
1)提示用户登录。在我们的案例中,我们自己创建oAuth2访问令牌或者我们可以代理您到facebook,github等...但是在一天结束时,驱动会话的oAuth2令牌for DynamicApis归我们所有。但如果完全由第三方(如GitHub)创作,则其余工作流程将完全相同。
2)用户使用email / passowrd登录。
3)用户使用授权码
重定向到DynamicApis.com4)DynamicApis.com交换访问令牌(服务器到服务器调用)的授权码。 此时我刚刚解释了oAuth2流程
5)此时我们(假设加密)代表该用户返回并发出的访问令牌,并将其用作会话提供者的密钥(让我们说基于Sql Server)。此会话提供商归DynamicApis.com所有。
6)现在您的会话提供程序正常工作。您有一个代表登录用户的密钥(散列/加密访问令牌)以及与该密钥关联的多个密钥/值。
您的会话提供程序将持久保存您要代表数据库中的用户存储的数据的会话状态(键值对)或您使用的任何内容
< / LI>会话提供者的截止日期应等于访问令牌的截止日期(或小于访问令牌的日期)。
当用户退出时会话被销毁。
会话密钥应以加密形式存在于cookie,网址中或隐藏在页面上(就像会话密钥今天一样)
7)噗。您有一个登录用户的会话。
如果您愿意,您实际上可以重用大部分内置的ASP.NET会话提供程序逻辑。或者您可以像在DynamicApis.com上一样建立自己的本土系统。
答案 1 :(得分:2)
如果可以的话,您可以在oauth实现中编写自己的自定义授权类和身份验证提供程序。
为此类身份验证定义新的客户端ID。
用户通过Facebook进行身份验证。
Facebook为客户生成令牌。
客户端向您的后端发送请求 应用此访问令牌,电子邮件地址和身份验证 类型/客户端ID(让我们说'facebook')
自定义授权决定令牌类型(Spring security-oauth implementation)
String clientId = tokenRequest.getClientId();
ClientDetails client = clientDetailsService.loadClientByClientId(clientId);
Map<String, String> parameters = tokenRequest.getRequestParameters();
String username = parameters.get("username"); //username is email
String password = parameters.get("password"); //password is fb access token
Authentication authentication = null;
if ("facebook".equals(clientId)) {
authentication = new FacebookAuthenticationToken(username, password);
} else {
authentication = new UserAuthenticationToken(username, password);
}
authentication = authenticationManager.authenticate(authentication);
身份验证提供程序检查facebook令牌并验证它。
public class FacebookAuthenticationProvider implements AuthenticationProvider {
@Autowired
private FacebookApi facebookApi;
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
String username = authentication.getName();
String password = (String) authentication.getCredentials();
// you can check your facebook session store
boolean valid = facebookApi.isValidToken(username, password);
if (!valid) {
throw new BadCredentialsException("Username not found.");
}
Collection<? extends GrantedAuthority> authorities = user.getAuthorities();
return new FacebookAuthenticationToken(user, password, authorities);
}
@Override
public boolean supports(Class<?> authentication) {
return FacebookAuthenticationToken.class.isAssignableFrom(authentication);
}
}
我把代码作为样本。
我经常强迫用户在第一次登录facebook(获取他们的电子邮件)后为我的内部应用设置密码。然后一切都变得简单了。你可以搞清楚我的意思。