#765 Retrieve the email address from Twitter.
This commit is contained in:
parent
f38ac2afff
commit
0bce133ee4
|
|
@ -125,9 +125,18 @@ namespace SocialSample
|
||||||
{
|
{
|
||||||
ConsumerKey = Configuration["twitter:consumerkey"],
|
ConsumerKey = Configuration["twitter:consumerkey"],
|
||||||
ConsumerSecret = Configuration["twitter:consumersecret"],
|
ConsumerSecret = Configuration["twitter:consumersecret"],
|
||||||
|
// http://stackoverflow.com/questions/22627083/can-we-get-email-id-from-twitter-oauth-api/32852370#32852370
|
||||||
|
// http://stackoverflow.com/questions/36330675/get-users-email-from-twitter-api-for-external-login-authentication-asp-net-mvc?lq=1
|
||||||
|
RetrieveUserDetails = true,
|
||||||
SaveTokens = true,
|
SaveTokens = true,
|
||||||
Events = new TwitterEvents()
|
Events = new TwitterEvents()
|
||||||
{
|
{
|
||||||
|
OnCreatingTicket = ctx =>
|
||||||
|
{
|
||||||
|
var profilePic = ctx.User.Value<string>("profile_image_url");
|
||||||
|
ctx.Principal.Identities.First().AddClaim(new Claim("urn:twitter:profilepicture", profilePic, ClaimTypes.Uri, ctx.Options.ClaimsIssuer));
|
||||||
|
return Task.FromResult(0);
|
||||||
|
},
|
||||||
OnRemoteFailure = ctx =>
|
OnRemoteFailure = ctx =>
|
||||||
{
|
{
|
||||||
ctx.Response.Redirect("/error?FailureMessage=" + UrlEncoder.Default.Encode(ctx.Failure.Message));
|
ctx.Response.Redirect("/error?FailureMessage=" + UrlEncoder.Default.Encode(ctx.Failure.Message));
|
||||||
|
|
@ -139,7 +148,7 @@ namespace SocialSample
|
||||||
|
|
||||||
/* Azure AD app model v2 has restrictions that prevent the use of plain HTTP for redirect URLs.
|
/* Azure AD app model v2 has restrictions that prevent the use of plain HTTP for redirect URLs.
|
||||||
Therefore, to authenticate through microsoft accounts, tryout the sample using the following URL:
|
Therefore, to authenticate through microsoft accounts, tryout the sample using the following URL:
|
||||||
https://localhost:54541/
|
https://localhost:44318/
|
||||||
*/
|
*/
|
||||||
// See config.json
|
// See config.json
|
||||||
// https://apps.dev.microsoft.com/
|
// https://apps.dev.microsoft.com/
|
||||||
|
|
@ -232,6 +241,14 @@ namespace SocialSample
|
||||||
ClaimValueTypes.String, context.Options.ClaimsIssuer));
|
ClaimValueTypes.String, context.Options.ClaimsIssuer));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var email = user.Value<string>("email");
|
||||||
|
if (!string.IsNullOrEmpty(email))
|
||||||
|
{
|
||||||
|
context.Identity.AddClaim(new Claim(
|
||||||
|
ClaimTypes.Email, email,
|
||||||
|
ClaimValueTypes.Email, context.Options.ClaimsIssuer));
|
||||||
|
}
|
||||||
|
|
||||||
var link = user.Value<string>("url");
|
var link = user.Value<string>("url");
|
||||||
if (!string.IsNullOrEmpty(link))
|
if (!string.IsNullOrEmpty(link))
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
{
|
{
|
||||||
"google:clientid": "560027070069-37ldt4kfuohhu3m495hk2j4pjp92d382.apps.googleusercontent.com",
|
"google:clientid": "560027070069-37ldt4kfuohhu3m495hk2j4pjp92d382.apps.googleusercontent.com",
|
||||||
"google:clientsecret": "n2Q-GEw9RQjzcRbU3qhfTj8f",
|
"google:clientsecret": "n2Q-GEw9RQjzcRbU3qhfTj8f",
|
||||||
"twitter:consumerkey": "6XaCTaLbMqfj6ww3zvZ5g",
|
"twitter:consumerkey": "VvNJRyGeqYBByN694UHudI2cv",
|
||||||
"twitter:consumersecret": "Il2eFzGIrYhz6BWjYhVXBPQSfZuS4xoHpSSyD9PI",
|
"twitter:consumersecret": "V2xEqWgmphPdlUXX4ARWsozl9lfbvr5wbAYw2LN8m6kZV7pt20",
|
||||||
"github:clientid": "49e302895d8b09ea5656",
|
"github:clientid": "49e302895d8b09ea5656",
|
||||||
"github:clientsecret": "98f1bf028608901e9df91d64ee61536fe562064b",
|
"github:clientsecret": "98f1bf028608901e9df91d64ee61536fe562064b",
|
||||||
"github-token:clientid": "8c0c5a572abe8fe89588",
|
"github-token:clientid": "8c0c5a572abe8fe89588",
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ using System.Security.Claims;
|
||||||
using Microsoft.AspNetCore.Builder;
|
using Microsoft.AspNetCore.Builder;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.Http.Authentication;
|
using Microsoft.AspNetCore.Http.Authentication;
|
||||||
|
using Newtonsoft.Json.Linq;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Authentication.Twitter
|
namespace Microsoft.AspNetCore.Authentication.Twitter
|
||||||
{
|
{
|
||||||
|
|
@ -22,40 +23,49 @@ namespace Microsoft.AspNetCore.Authentication.Twitter
|
||||||
/// <param name="screenName">Twitter screen name</param>
|
/// <param name="screenName">Twitter screen name</param>
|
||||||
/// <param name="accessToken">Twitter access token</param>
|
/// <param name="accessToken">Twitter access token</param>
|
||||||
/// <param name="accessTokenSecret">Twitter access token secret</param>
|
/// <param name="accessTokenSecret">Twitter access token secret</param>
|
||||||
|
/// <param name="user">User details</param>
|
||||||
public TwitterCreatingTicketContext(
|
public TwitterCreatingTicketContext(
|
||||||
HttpContext context,
|
HttpContext context,
|
||||||
TwitterOptions options,
|
TwitterOptions options,
|
||||||
string userId,
|
string userId,
|
||||||
string screenName,
|
string screenName,
|
||||||
string accessToken,
|
string accessToken,
|
||||||
string accessTokenSecret)
|
string accessTokenSecret,
|
||||||
|
JObject user)
|
||||||
: base(context, options)
|
: base(context, options)
|
||||||
{
|
{
|
||||||
UserId = userId;
|
UserId = userId;
|
||||||
ScreenName = screenName;
|
ScreenName = screenName;
|
||||||
AccessToken = accessToken;
|
AccessToken = accessToken;
|
||||||
AccessTokenSecret = accessTokenSecret;
|
AccessTokenSecret = accessTokenSecret;
|
||||||
|
User = user ?? new JObject();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the Twitter user ID
|
/// Gets the Twitter user ID
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string UserId { get; private set; }
|
public string UserId { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the Twitter screen name
|
/// Gets the Twitter screen name
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string ScreenName { get; private set; }
|
public string ScreenName { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the Twitter access token
|
/// Gets the Twitter access token
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string AccessToken { get; private set; }
|
public string AccessToken { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the Twitter access token secret
|
/// Gets the Twitter access token secret
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string AccessTokenSecret { get; private set; }
|
public string AccessTokenSecret { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the JSON-serialized user or an empty
|
||||||
|
/// <see cref="JObject"/> if it is not available.
|
||||||
|
/// </summary>
|
||||||
|
public JObject User { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the <see cref="ClaimsPrincipal"/> representing the user
|
/// Gets the <see cref="ClaimsPrincipal"/> representing the user
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ namespace Microsoft.Extensions.Logging
|
||||||
{
|
{
|
||||||
private static Action<ILogger, Exception> _obtainRequestToken;
|
private static Action<ILogger, Exception> _obtainRequestToken;
|
||||||
private static Action<ILogger, Exception> _obtainAccessToken;
|
private static Action<ILogger, Exception> _obtainAccessToken;
|
||||||
|
private static Action<ILogger, Exception> _retrieveUserDetails;
|
||||||
|
|
||||||
static LoggingExtensions()
|
static LoggingExtensions()
|
||||||
{
|
{
|
||||||
|
|
@ -20,6 +21,10 @@ namespace Microsoft.Extensions.Logging
|
||||||
eventId: 2,
|
eventId: 2,
|
||||||
logLevel: LogLevel.Debug,
|
logLevel: LogLevel.Debug,
|
||||||
formatString: "ObtainAccessToken");
|
formatString: "ObtainAccessToken");
|
||||||
|
_retrieveUserDetails = LoggerMessage.Define(
|
||||||
|
eventId: 3,
|
||||||
|
logLevel: LogLevel.Debug,
|
||||||
|
formatString: "RetrieveUserDetails");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -32,5 +37,10 @@ namespace Microsoft.Extensions.Logging
|
||||||
{
|
{
|
||||||
_obtainRequestToken(logger, null);
|
_obtainRequestToken(logger, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void RetrieveUserDetails(this ILogger logger)
|
||||||
|
{
|
||||||
|
_retrieveUserDetails(logger, null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ using Microsoft.AspNetCore.Http.Features.Authentication;
|
||||||
using Microsoft.AspNetCore.WebUtilities;
|
using Microsoft.AspNetCore.WebUtilities;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Microsoft.Extensions.Primitives;
|
using Microsoft.Extensions.Primitives;
|
||||||
|
using Newtonsoft.Json.Linq;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Authentication.Twitter
|
namespace Microsoft.AspNetCore.Authentication.Twitter
|
||||||
{
|
{
|
||||||
|
|
@ -76,7 +77,7 @@ namespace Microsoft.AspNetCore.Authentication.Twitter
|
||||||
|
|
||||||
Response.Cookies.Delete(StateCookie, cookieOptions);
|
Response.Cookies.Delete(StateCookie, cookieOptions);
|
||||||
|
|
||||||
var accessToken = await ObtainAccessTokenAsync(Options.ConsumerKey, Options.ConsumerSecret, requestToken, oauthVerifier);
|
var accessToken = await ObtainAccessTokenAsync(requestToken, oauthVerifier);
|
||||||
|
|
||||||
var identity = new ClaimsIdentity(new[]
|
var identity = new ClaimsIdentity(new[]
|
||||||
{
|
{
|
||||||
|
|
@ -87,6 +88,12 @@ namespace Microsoft.AspNetCore.Authentication.Twitter
|
||||||
},
|
},
|
||||||
Options.ClaimsIssuer);
|
Options.ClaimsIssuer);
|
||||||
|
|
||||||
|
JObject user = null;
|
||||||
|
if (Options.RetrieveUserDetails)
|
||||||
|
{
|
||||||
|
user = await RetrieveUserDetailsAsync(accessToken, identity);
|
||||||
|
}
|
||||||
|
|
||||||
if (Options.SaveTokens)
|
if (Options.SaveTokens)
|
||||||
{
|
{
|
||||||
properties.StoreTokens(new [] {
|
properties.StoreTokens(new [] {
|
||||||
|
|
@ -95,12 +102,13 @@ namespace Microsoft.AspNetCore.Authentication.Twitter
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return AuthenticateResult.Success(await CreateTicketAsync(identity, properties, accessToken));
|
return AuthenticateResult.Success(await CreateTicketAsync(identity, properties, accessToken, user));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual async Task<AuthenticationTicket> CreateTicketAsync(ClaimsIdentity identity, AuthenticationProperties properties, AccessToken token)
|
protected virtual async Task<AuthenticationTicket> CreateTicketAsync(
|
||||||
|
ClaimsIdentity identity, AuthenticationProperties properties, AccessToken token, JObject user)
|
||||||
{
|
{
|
||||||
var context = new TwitterCreatingTicketContext(Context, Options, token.UserId, token.ScreenName, token.Token, token.TokenSecret)
|
var context = new TwitterCreatingTicketContext(Context, Options, token.UserId, token.ScreenName, token.Token, token.TokenSecret, user)
|
||||||
{
|
{
|
||||||
Principal = new ClaimsPrincipal(identity),
|
Principal = new ClaimsPrincipal(identity),
|
||||||
Properties = properties
|
Properties = properties
|
||||||
|
|
@ -134,7 +142,7 @@ namespace Microsoft.AspNetCore.Authentication.Twitter
|
||||||
}
|
}
|
||||||
|
|
||||||
// If CallbackConfirmed is false, this will throw
|
// If CallbackConfirmed is false, this will throw
|
||||||
var requestToken = await ObtainRequestTokenAsync(Options.ConsumerKey, Options.ConsumerSecret, BuildRedirectUri(Options.CallbackPath), properties);
|
var requestToken = await ObtainRequestTokenAsync(BuildRedirectUri(Options.CallbackPath), properties);
|
||||||
var twitterAuthenticationEndpoint = AuthenticationEndpoint + requestToken.Token;
|
var twitterAuthenticationEndpoint = AuthenticationEndpoint + requestToken.Token;
|
||||||
|
|
||||||
var cookieOptions = new CookieOptions
|
var cookieOptions = new CookieOptions
|
||||||
|
|
@ -152,7 +160,7 @@ namespace Microsoft.AspNetCore.Authentication.Twitter
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<RequestToken> ObtainRequestTokenAsync(string consumerKey, string consumerSecret, string callBackUri, AuthenticationProperties properties)
|
private async Task<RequestToken> ObtainRequestTokenAsync(string callBackUri, AuthenticationProperties properties)
|
||||||
{
|
{
|
||||||
Logger.ObtainRequestToken();
|
Logger.ObtainRequestToken();
|
||||||
|
|
||||||
|
|
@ -161,7 +169,7 @@ namespace Microsoft.AspNetCore.Authentication.Twitter
|
||||||
var authorizationParts = new SortedDictionary<string, string>
|
var authorizationParts = new SortedDictionary<string, string>
|
||||||
{
|
{
|
||||||
{ "oauth_callback", callBackUri },
|
{ "oauth_callback", callBackUri },
|
||||||
{ "oauth_consumer_key", consumerKey },
|
{ "oauth_consumer_key", Options.ConsumerKey },
|
||||||
{ "oauth_nonce", nonce },
|
{ "oauth_nonce", nonce },
|
||||||
{ "oauth_signature_method", "HMAC-SHA1" },
|
{ "oauth_signature_method", "HMAC-SHA1" },
|
||||||
{ "oauth_timestamp", GenerateTimeStamp() },
|
{ "oauth_timestamp", GenerateTimeStamp() },
|
||||||
|
|
@ -183,7 +191,7 @@ namespace Microsoft.AspNetCore.Authentication.Twitter
|
||||||
canonicalizedRequestBuilder.Append("&");
|
canonicalizedRequestBuilder.Append("&");
|
||||||
canonicalizedRequestBuilder.Append(UrlEncoder.Encode(parameterString));
|
canonicalizedRequestBuilder.Append(UrlEncoder.Encode(parameterString));
|
||||||
|
|
||||||
var signature = ComputeSignature(consumerSecret, null, canonicalizedRequestBuilder.ToString());
|
var signature = ComputeSignature(Options.ConsumerSecret, null, canonicalizedRequestBuilder.ToString());
|
||||||
authorizationParts.Add("oauth_signature", signature);
|
authorizationParts.Add("oauth_signature", signature);
|
||||||
|
|
||||||
var authorizationHeaderBuilder = new StringBuilder();
|
var authorizationHeaderBuilder = new StringBuilder();
|
||||||
|
|
@ -200,7 +208,7 @@ namespace Microsoft.AspNetCore.Authentication.Twitter
|
||||||
|
|
||||||
var response = await _httpClient.SendAsync(request, Context.RequestAborted);
|
var response = await _httpClient.SendAsync(request, Context.RequestAborted);
|
||||||
response.EnsureSuccessStatusCode();
|
response.EnsureSuccessStatusCode();
|
||||||
string responseText = await response.Content.ReadAsStringAsync();
|
var responseText = await response.Content.ReadAsStringAsync();
|
||||||
|
|
||||||
var responseParameters = new FormCollection(new FormReader(responseText).ReadForm());
|
var responseParameters = new FormCollection(new FormReader(responseText).ReadForm());
|
||||||
if (!string.Equals(responseParameters["oauth_callback_confirmed"], "true", StringComparison.Ordinal))
|
if (!string.Equals(responseParameters["oauth_callback_confirmed"], "true", StringComparison.Ordinal))
|
||||||
|
|
@ -211,7 +219,7 @@ namespace Microsoft.AspNetCore.Authentication.Twitter
|
||||||
return new RequestToken { Token = Uri.UnescapeDataString(responseParameters["oauth_token"]), TokenSecret = Uri.UnescapeDataString(responseParameters["oauth_token_secret"]), CallbackConfirmed = true, Properties = properties };
|
return new RequestToken { Token = Uri.UnescapeDataString(responseParameters["oauth_token"]), TokenSecret = Uri.UnescapeDataString(responseParameters["oauth_token_secret"]), CallbackConfirmed = true, Properties = properties };
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<AccessToken> ObtainAccessTokenAsync(string consumerKey, string consumerSecret, RequestToken token, string verifier)
|
private async Task<AccessToken> ObtainAccessTokenAsync(RequestToken token, string verifier)
|
||||||
{
|
{
|
||||||
// https://dev.twitter.com/docs/api/1/post/oauth/access_token
|
// https://dev.twitter.com/docs/api/1/post/oauth/access_token
|
||||||
|
|
||||||
|
|
@ -221,7 +229,7 @@ namespace Microsoft.AspNetCore.Authentication.Twitter
|
||||||
|
|
||||||
var authorizationParts = new SortedDictionary<string, string>
|
var authorizationParts = new SortedDictionary<string, string>
|
||||||
{
|
{
|
||||||
{ "oauth_consumer_key", consumerKey },
|
{ "oauth_consumer_key", Options.ConsumerKey },
|
||||||
{ "oauth_nonce", nonce },
|
{ "oauth_nonce", nonce },
|
||||||
{ "oauth_signature_method", "HMAC-SHA1" },
|
{ "oauth_signature_method", "HMAC-SHA1" },
|
||||||
{ "oauth_token", token.Token },
|
{ "oauth_token", token.Token },
|
||||||
|
|
@ -245,7 +253,7 @@ namespace Microsoft.AspNetCore.Authentication.Twitter
|
||||||
canonicalizedRequestBuilder.Append("&");
|
canonicalizedRequestBuilder.Append("&");
|
||||||
canonicalizedRequestBuilder.Append(UrlEncoder.Encode(parameterString));
|
canonicalizedRequestBuilder.Append(UrlEncoder.Encode(parameterString));
|
||||||
|
|
||||||
var signature = ComputeSignature(consumerSecret, token.TokenSecret, canonicalizedRequestBuilder.ToString());
|
var signature = ComputeSignature(Options.ConsumerSecret, token.TokenSecret, canonicalizedRequestBuilder.ToString());
|
||||||
authorizationParts.Add("oauth_signature", signature);
|
authorizationParts.Add("oauth_signature", signature);
|
||||||
authorizationParts.Remove("oauth_verifier");
|
authorizationParts.Remove("oauth_verifier");
|
||||||
|
|
||||||
|
|
@ -288,6 +296,76 @@ namespace Microsoft.AspNetCore.Authentication.Twitter
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// https://dev.twitter.com/rest/reference/get/account/verify_credentials
|
||||||
|
private async Task<JObject> RetrieveUserDetailsAsync(AccessToken accessToken, ClaimsIdentity identity)
|
||||||
|
{
|
||||||
|
Logger.RetrieveUserDetails();
|
||||||
|
|
||||||
|
var nonce = Guid.NewGuid().ToString("N");
|
||||||
|
|
||||||
|
var authorizationParts = new SortedDictionary<string, string>
|
||||||
|
{
|
||||||
|
{ "oauth_consumer_key", Options.ConsumerKey },
|
||||||
|
{ "oauth_nonce", nonce },
|
||||||
|
{ "oauth_signature_method", "HMAC-SHA1" },
|
||||||
|
{ "oauth_timestamp", GenerateTimeStamp() },
|
||||||
|
{ "oauth_token", accessToken.Token },
|
||||||
|
{ "oauth_version", "1.0" }
|
||||||
|
};
|
||||||
|
|
||||||
|
var parameterBuilder = new StringBuilder();
|
||||||
|
foreach (var authorizationKey in authorizationParts)
|
||||||
|
{
|
||||||
|
parameterBuilder.AppendFormat("{0}={1}&", UrlEncoder.Encode(authorizationKey.Key), UrlEncoder.Encode(authorizationKey.Value));
|
||||||
|
}
|
||||||
|
parameterBuilder.Length--;
|
||||||
|
var parameterString = parameterBuilder.ToString();
|
||||||
|
|
||||||
|
var resource_url = "https://api.twitter.com/1.1/account/verify_credentials.json";
|
||||||
|
var resource_query = "include_email=true";
|
||||||
|
var canonicalizedRequestBuilder = new StringBuilder();
|
||||||
|
canonicalizedRequestBuilder.Append(HttpMethod.Get.Method);
|
||||||
|
canonicalizedRequestBuilder.Append("&");
|
||||||
|
canonicalizedRequestBuilder.Append(UrlEncoder.Encode(resource_url));
|
||||||
|
canonicalizedRequestBuilder.Append("&");
|
||||||
|
canonicalizedRequestBuilder.Append(UrlEncoder.Encode(resource_query));
|
||||||
|
canonicalizedRequestBuilder.Append("%26");
|
||||||
|
canonicalizedRequestBuilder.Append(UrlEncoder.Encode(parameterString));
|
||||||
|
|
||||||
|
var signature = ComputeSignature(Options.ConsumerSecret, accessToken.TokenSecret, canonicalizedRequestBuilder.ToString());
|
||||||
|
authorizationParts.Add("oauth_signature", signature);
|
||||||
|
|
||||||
|
var authorizationHeaderBuilder = new StringBuilder();
|
||||||
|
authorizationHeaderBuilder.Append("OAuth ");
|
||||||
|
foreach (var authorizationPart in authorizationParts)
|
||||||
|
{
|
||||||
|
authorizationHeaderBuilder.AppendFormat(
|
||||||
|
"{0}=\"{1}\", ", authorizationPart.Key, UrlEncoder.Encode(authorizationPart.Value));
|
||||||
|
}
|
||||||
|
authorizationHeaderBuilder.Length = authorizationHeaderBuilder.Length - 2;
|
||||||
|
|
||||||
|
var request = new HttpRequestMessage(HttpMethod.Get, resource_url + "?include_email=true");
|
||||||
|
request.Headers.Add("Authorization", authorizationHeaderBuilder.ToString());
|
||||||
|
|
||||||
|
var response = await _httpClient.SendAsync(request, Context.RequestAborted);
|
||||||
|
if (!response.IsSuccessStatusCode)
|
||||||
|
{
|
||||||
|
Logger.LogError("Email request failed with a status code of " + response.StatusCode);
|
||||||
|
response.EnsureSuccessStatusCode(); // throw
|
||||||
|
}
|
||||||
|
var responseText = await response.Content.ReadAsStringAsync();
|
||||||
|
|
||||||
|
var result = JObject.Parse(responseText);
|
||||||
|
|
||||||
|
var email = result.Value<string>("email");
|
||||||
|
if (!string.IsNullOrEmpty(email))
|
||||||
|
{
|
||||||
|
identity.AddClaim(new Claim(ClaimTypes.Email, email, ClaimValueTypes.Email, Options.ClaimsIssuer));
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
private static string GenerateTimeStamp()
|
private static string GenerateTimeStamp()
|
||||||
{
|
{
|
||||||
var secondsSinceUnixEpocStart = DateTime.UtcNow - Epoch;
|
var secondsSinceUnixEpocStart = DateTime.UtcNow - Epoch;
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,14 @@ namespace Microsoft.AspNetCore.Builder
|
||||||
/// <value>The consumer secret used to sign requests to Twitter.</value>
|
/// <value>The consumer secret used to sign requests to Twitter.</value>
|
||||||
public string ConsumerSecret { get; set; }
|
public string ConsumerSecret { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Enables the retrieval user details during the authentication process, including
|
||||||
|
/// e-mail addresses. Retrieving e-mail addresses requires special permissions
|
||||||
|
/// from Twitter Support on a per application basis. The default is false.
|
||||||
|
/// See https://dev.twitter.com/rest/reference/get/account/verify_credentials
|
||||||
|
/// </summary>
|
||||||
|
public bool RetrieveUserDetails { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the type used to secure data handled by the middleware.
|
/// Gets or sets the type used to secure data handled by the middleware.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
||||||
|
|
@ -19,10 +19,15 @@
|
||||||
"xmlDoc": true
|
"xmlDoc": true
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"Microsoft.AspNetCore.Authentication": "1.0.0-*"
|
"Microsoft.AspNetCore.Authentication": "1.0.0-*",
|
||||||
|
"Newtonsoft.Json": "8.0.3"
|
||||||
},
|
},
|
||||||
"frameworks": {
|
"frameworks": {
|
||||||
"net451": {},
|
"net451": {},
|
||||||
"netstandard1.3": {}
|
"netstandard1.3": {
|
||||||
|
"imports": [
|
||||||
|
"portable-net451+win8"
|
||||||
|
]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Loading…
Reference in New Issue