-
Notifications
You must be signed in to change notification settings - Fork 1.6k
/
FacebookAuthProvider.cs
158 lines (134 loc) · 7.08 KB
/
FacebookAuthProvider.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
using System;
using System.Collections.Generic;
using System.Net;
using System.Web;
using ServiceStack.Configuration;
using ServiceStack.Text;
namespace ServiceStack.Auth
{
/// <summary>
/// Create a Facebook App at: https://developers.facebook.com/apps
/// The Callback URL for your app should match the CallbackUrl provided.
/// </summary>
public class FacebookAuthProvider : OAuthProvider
{
public const string Name = "facebook";
public static string Realm = "https://graph.facebook.com/v2.8/";
public static string PreAuthUrl = "https://www.facebook.com/dialog/oauth";
public static string[] DefaultFields = { "id", "name", "first_name", "last_name", "email" };
public string AppId { get; set; }
public string AppSecret { get; set; }
public string[] Permissions { get; set; }
public string[] Fields { get; set; }
public FacebookAuthProvider(IAppSettings appSettings)
: base(appSettings, Realm, Name, "AppId", "AppSecret")
{
this.AppId = appSettings.GetString("oauth.facebook.AppId");
this.AppSecret = appSettings.GetString("oauth.facebook.AppSecret");
this.Permissions = appSettings.Get("oauth.facebook.Permissions", TypeConstants.EmptyStringArray);
this.Fields = appSettings.Get("oauth.facebook.Fields", DefaultFields);
}
public override object Authenticate(IServiceBase authService, IAuthSession session, Authenticate request)
{
var tokens = Init(authService, ref session, request);
//Transfering AccessToken/Secret from Mobile/Desktop App to Server
if (request.AccessToken != null)
{
tokens.AccessTokenSecret = request.AccessToken;
if (!AuthHttpGateway.VerifyFacebookAccessToken(AppId, tokens.AccessTokenSecret))
return HttpError.Unauthorized("AccessToken is not for App: " + AppId);
session.IsAuthenticated = true;
var authResponse = OnAuthenticated(authService, session, tokens, new Dictionary<string, string>());
if (authResponse != null)
return authResponse;
var isHtml = authService.Request.ResponseContentType.MatchesContentType(MimeTypes.Html);
return isHtml
? authService.Redirect(SuccessRedirectUrlFilter(this, session.ReferrerUrl.SetParam("s", "1")))
: null; //return default AuthenticateResponse
}
var httpRequest = authService.Request;
var error = httpRequest.QueryString["error_reason"]
?? httpRequest.QueryString["error"]
?? httpRequest.QueryString["error_code"]
?? httpRequest.QueryString["error_description"];
var hasError = !error.IsNullOrEmpty();
if (hasError)
{
Log.Error($"Facebook error callback. {httpRequest.QueryString}");
return authService.Redirect(FailedRedirectUrlFilter(this, session.ReferrerUrl.SetParam("f", error)));
}
var code = httpRequest.QueryString["code"];
var isPreAuthCallback = !code.IsNullOrEmpty();
if (!isPreAuthCallback)
{
var preAuthUrl = $"{PreAuthUrl}?client_id={AppId}&redirect_uri={this.CallbackUrl.UrlEncode()}&scope={string.Join(",", Permissions)}";
this.SaveSession(authService, session, SessionExpiry);
return authService.Redirect(PreAuthUrlFilter(this, preAuthUrl));
}
var accessTokenUrl = $"{AccessTokenUrl}?client_id={AppId}&redirect_uri={this.CallbackUrl.UrlEncode()}&client_secret={AppSecret}&code={code}";
try
{
var contents = AccessTokenUrlFilter(this, accessTokenUrl).GetJsonFromUrl();
var authInfo = JsonObject.Parse(contents);
tokens.AccessTokenSecret = authInfo["access_token"];
session.IsAuthenticated = true;
return OnAuthenticated(authService, session, tokens, authInfo.ToDictionary())
?? authService.Redirect(SuccessRedirectUrlFilter(this, session.ReferrerUrl.SetParam("s", "1"))); //Haz access!
}
catch (WebException we)
{
var statusCode = ((HttpWebResponse)we.Response).StatusCode;
if (statusCode == HttpStatusCode.BadRequest)
{
return authService.Redirect(FailedRedirectUrlFilter(this, session.ReferrerUrl.SetParam("f", "AccessTokenFailed")));
}
}
//Shouldn't get here
return authService.Redirect(FailedRedirectUrlFilter(this, session.ReferrerUrl.SetParam("f", "Unknown")));
}
protected override void LoadUserAuthInfo(AuthUserSession userSession, IAuthTokens tokens, Dictionary<string, string> authInfo)
{
try
{
var json = AuthHttpGateway.DownloadFacebookUserInfo(tokens.AccessTokenSecret, Fields);
var obj = JsonObject.Parse(json);
tokens.UserId = obj.Get("id");
tokens.UserName = obj.Get("id") ?? obj.Get("username");
tokens.DisplayName = obj.Get("name");
tokens.FirstName = obj.Get("first_name");
tokens.LastName = obj.Get("last_name");
tokens.Email = obj.Get("email");
if (SaveExtendedUserInfo)
{
obj.Each(x => authInfo[x.Key] = x.Value);
}
json = AuthHttpGateway.DownloadFacebookUserInfo(tokens.AccessTokenSecret, "picture");
obj = JsonObject.Parse(json);
var picture = obj.Object("picture");
var data = picture?.Object("data");
if (data != null)
{
string profileUrl;
if (data.TryGetValue("url", out profileUrl))
tokens.Items[AuthMetadataProvider.ProfileUrlKey] = profileUrl.SanitizeOAuthUrl();
}
}
catch (Exception ex)
{
Log.Error($"Could not retrieve facebook user info for '{tokens.DisplayName}'", ex);
}
LoadUserOAuthProvider(userSession, tokens);
}
public override void LoadUserOAuthProvider(IAuthSession authSession, IAuthTokens tokens)
{
var userSession = authSession as AuthUserSession;
if (userSession == null) return;
userSession.FacebookUserId = tokens.UserId ?? userSession.FacebookUserId;
userSession.FacebookUserName = tokens.UserName ?? userSession.FacebookUserName;
userSession.DisplayName = tokens.DisplayName ?? userSession.DisplayName;
userSession.FirstName = tokens.FirstName ?? userSession.FirstName;
userSession.LastName = tokens.LastName ?? userSession.LastName;
userSession.PrimaryEmail = tokens.Email ?? userSession.PrimaryEmail ?? userSession.Email;
}
}
}