JWT ValidateToken overriding in C# - c#

I have setup a token authentication process and its working quite well. I am using OWIN.
I am extending 2 specific points which lets me control the signing of the JWT and also the validating of user credentials like so.
Provider = new MyOAuthProvider(),
AccessTokenFormat = new MyJwtFormatter()
How do I hook into the part where the token is being validated. I searched the web and it appears there is a method can't ValidateToken that you can override but I don't know where this is.
I also have the following. Do I need to override something here ?
app.UseJwtBearerAuthentication(
new JwtBearerAuthenticationOptions
{
AuthenticationMode = AuthenticationMode.Active,
AllowedAudiences = new[] { audience },
IssuerSecurityTokenProviders =
new IIssuerSecurityTokenProvider[]
{
new SymmetricKeyIssuerSecurityTokenProvider(
issuer,
secret)
}
});
What might I be missing? Most of the things I have found support what I am doing but not hooking into the token authentication.
I believe its using the internal JWTTokenHandler, I presume you can override this or something?

Here's simple JWT Validation class based on: Google Sign-In for Websites
using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens;
using System.Linq;
using System.Net.Http;
using System.Web;
using System.Web.Configuration;
using Newtonsoft.Json;
using System.Net;
using System.Threading.Tasks;
using System.Threading;
using Services.Models;
using System.Security.Claims;
namespace Services
{
/// <summary>
/// This is an implementation of Google JWT verification that
/// demonstrates:
/// - JWT validation
/// </summary>
/// #author kunal.bajpai#gmail.com (Kunal Bajpai)
public class CustomJwtHandler : DelegatingHandler
{
string issuer = WebConfigurationManager.AppSettings["GoogleDomain"];
string audience = WebConfigurationManager.AppSettings["GoogleClientId"];
/// <summary>
///
/// </summary>
/// <param name="request"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
HttpStatusCode statusCode;
string token;
var authHeader = request.Headers.Authorization;
if (authHeader == null)
{
// Missing authorization header
return base.SendAsync(request, cancellationToken);
}
if (!TryRetrieveToken(request, out token))
{
return Task<HttpResponseMessage>.Factory.StartNew(() => new HttpResponseMessage(HttpStatusCode.Unauthorized));
}
try
{
ValidateToken(token);
return base.SendAsync(request, cancellationToken);
}
catch (SecurityTokenInvalidAudienceException)
{
statusCode = HttpStatusCode.Unauthorized;
}
catch (SecurityTokenValidationException)
{
statusCode = HttpStatusCode.Unauthorized;
}
catch (Exception e)
{
statusCode = HttpStatusCode.InternalServerError;
}
return Task<HttpResponseMessage>.Factory.StartNew(() => new HttpResponseMessage(statusCode));
}
/// <summary>
/// Validates JWT Token
/// </summary>
/// <param name="token"></param>
private void ValidateToken(string token)
{
try
{
using (WebClient wc = new WebClient())
{
TokenInfo tokenInfo = JsonConvert.DeserializeObject<TokenInfo>(wc.DownloadString("https://www.googleapis.com/oauth2/v3/tokeninfo?id_token=" + token));
List<Claim> claims = new List<Claim> {
new Claim(ClaimTypes.Name, tokenInfo.Name),
new Claim(ClaimTypes.Email, tokenInfo.Email),
new Claim(ClaimTypes.GivenName, tokenInfo.GivenName),
new Claim(ClaimTypes.Surname, tokenInfo.FamilyName),
};
ClaimsPrincipal claimsPrincipal = new ClaimsPrincipal(new ClaimsIdentity(claims, tokenInfo.Issuer));
Thread.CurrentPrincipal = claimsPrincipal;
HttpContext.Current.User = claimsPrincipal;
}
}
catch (WebException e)
{
HttpStatusCode statusCode = ((HttpWebResponse)e.Response).StatusCode;
if (statusCode == HttpStatusCode.BadRequest)
{
throw new SecurityTokenValidationException();
}
else
{
throw new Exception();
}
}
}
/// <summary>
/// Tries to retrieve Token
/// </summary>
/// <param name="request"></param>
/// <param name="token"></param>
/// <returns></returns>
private static bool TryRetrieveToken(HttpRequestMessage request, out string token)
{
token = null;
IEnumerable<string> authorizationHeaders;
if (!request.Headers.TryGetValues("Authorization", out authorizationHeaders) ||
authorizationHeaders.Count() > 1)
{
return false;
}
var bearerToken = authorizationHeaders.ElementAt(0);
token = bearerToken.StartsWith("Bearer ") ? bearerToken.Substring(7) : bearerToken;
return true;
}
}
}

Related

.NET 7 MAUI not receiving http response

I am playing around with .NET MAUI, and I got a problem. I call a rest API endpoint, and it is called, no errors (works 100% because I got response in Postman and on the SwaggerUI). But my mobile app client never receives a response. I probably miss something. Any idea is welcome.
namespace Mobile.UI.Clients;
public abstract class BaseClient
{
private readonly HttpClient httpClient;
private readonly MobileAppSettings settings;
private string BaseURL
{
get
{
return DeviceInfo.Platform == DevicePlatform.Android ?
this.settings.AndroidBaseURL :
this.settings.IosBaseURL;
}
}
protected BaseClient(HttpClient httpClient, MobileAppSettings settings)
{
this.settings = settings;
this.httpClient = BuildHttpClient(httpClient);
}
/// <summary>
/// Creates a simple get request
/// </summary>
/// <typeparam name="T">The return type</typeparam>
/// <param name="route">The route part without the base url</param>
/// <returns></returns>
/// <exception cref="Exception"></exception>
protected async Task<T> SendGetRequestAsync<T>(string route)
{
try
{
var uri = BuildUri(route);
var response = await httpClient.GetAsync(uri);
if (!response.IsSuccessStatusCode)
{
throw new Exception("Faild to fetch data.");
}
var content = await SerializeResponse<T>(response.Content);
return content;
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
}
/// <summary>
/// Creates a simple get request
/// </summary>
/// <typeparam name="T">The return type</typeparam>
/// <param name="route">The route part without the base url</param>
/// <param name="routParam">Rout parameter</param>
/// <returns></returns>
/// <exception cref="Exception"></exception>
protected async Task<T> SendGetRequestAsync<T>(string route, object routParam)
{
try
{
var uri = BuildUri(route, routParam);
var response = await httpClient.GetAsync(uri);
if (!response.IsSuccessStatusCode)
{
throw new Exception("Faild to fetch data.");
}
var content = await SerializeResponse<T>(response.Content);
return content;
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
}
private HttpClient BuildHttpClient(HttpClient httpClient)
{
#if DEBUG
var handler = new HttpsClientHandlerService();
httpClient = new HttpClient(handler.GetPlatformMessageHandler());
#endif
httpClient.BaseAddress = new Uri(BaseURL);
httpClient.DefaultRequestHeaders.Add("Cache-Control", "no-cache");
httpClient.DefaultRequestHeaders.Add("Accept-Encoding", "gzip, deflate, br");
httpClient.DefaultRequestHeaders.Accept.Clear();
httpClient.DefaultRequestHeaders.Accept.Add(new("application/json"));
return httpClient;
}
private Uri BuildUri(string route)
{
return new Uri(Path.Combine(BaseURL, settings.ApiVersion, route));
}
private Uri BuildUri(string route, object routParam)
{
return new Uri(Path.Combine(BaseURL, settings.ApiVersion, route, $"{routParam}"));
}
private async Task<T> SerializeResponse<T>(HttpContent content)
{
var stream = await content.ReadAsStreamAsync();
return await JsonSerializer.DeserializeAsync<T>(stream);
}
}
public class PlayerClient : BaseClient, IPlayerClient
{
public PlayerClient(HttpClient httpClient, MobileAppSettings settings) : base(httpClient, settings)
{}
public async Task<List<PlayerModel>> GetAllAsync()
{
var path = #"players/get-all";
return await SendGetRequestAsync<List<PlayerModel>>(path);
}
}
public class HttpsClientHandlerService : IHttpsClientHandlerService
{
public HttpMessageHandler GetPlatformMessageHandler()
{
#if ANDROID
var handler = new Xamarin.Android.Net.AndroidMessageHandler();
handler.ServerCertificateCustomValidationCallback = (message, cert, chain, errors) =>
{
if (cert != null && cert.Issuer.Equals("CN=localhost"))
return true;
return errors == System.Net.Security.SslPolicyErrors.None;
};
return handler;
#elif IOS
var handler = new NSUrlSessionHandler
{
TrustOverrideForUrl = IsHttpsLocalhost
};
return handler;
#elif WINDOWS || MACCATALYST
return null;
#else
throw new PlatformNotSupportedException("Only Android, iOS, MacCatalyst, and Windows supported.");
#endif
}
#if IOS
public bool IsHttpsLocalhost(NSUrlSessionHandler sender, string url, Security.SecTrust trust)
{
if (url.StartsWith("https://localhost"))
return true;
return false;
}
#endif
}
In the android message handler I captured an error (if it is an error):
System.Net.Security.SslPolicyErrors.RemoteCertificateChainErrors | System.Net.Security.SslPolicyErrors.RemoteCertificateNameMismatch

How to implement a custom IAuthenticationModule for bearer tokens with RestSharp

I am using RestSharp to make requests to an API which uses bearer token authentication. Most requests run as expected, but there is a specific endpoint which always redirects the request to a dynamic location. When this redirect occurs, the Authorization header is lost (by design), thus resulting in a Bad Request.
I've done some looking into the issue and found one similar issue here, but the custom AuthenticationModule I made is never having the Authenticate function called.
Am I missing something obvious in the setup that is preventing the Authentication module from being used, or is something else going on?
Thanks!
My Authenticator class:
public class AdpAuthenticator : IAuthenticator
{
/// <summary>
/// The current access token for making requests to the API.
/// </summary>
private static string AccessToken { get; set; }
/// <summary>
/// When the current access token expires.
/// </summary>
private static DateTime TokenExpiresOn { get; set; }
private static CredentialCache CredentialCache { get; set; }
/// <summary>
/// Singleton instance for making requests for access tokens.
/// </summary>
private static IRestClient AuthenticationClient { get; set; }
/// <summary>
/// Singleton instance of the request for obtaining access tokens.
/// </summary>
private static IRestRequest AuthenticationRequest { get; set; }
/// <summary>
/// Construct a new AdpAuthenticator.
/// </summary>
/// <param name="adpClientId"></param>
/// <param name="adpClientSecret"></param>
/// <param name="adpCertPath"></param>
public AdpAuthenticator(string adpClientId, string adpClientSecret, string adpCertPath)
{
if (string.IsNullOrWhiteSpace(adpClientId)) throw new ArgumentNullException("Passed adpClientId was empty or null.");
if (string.IsNullOrWhiteSpace(adpClientSecret)) throw new ArgumentNullException("Passed adpClientSecret was empty or null.");
if (CredentialCache == null)
{
CredentialCache = new CredentialCache
{
{new Uri("https://api.adp.com"), "Basic", new NetworkCredential(adpClientId, adpClientSecret) }
};
}
if (AuthenticationClient == null)
{
X509Certificate2Collection certificateCollection;
X509Certificate2 certificate = new X509Certificate2(adpCertPath);
certificateCollection = new X509Certificate2Collection
{
certificate
};
AuthenticationClient = new RestClient("https://api.adp.com")
{
ClientCertificates = certificateCollection,
Authenticator = new HttpBasicAuthenticator(adpClientId, adpClientSecret)
};
AuthenticationClient.UseSerializer(new JsonNetSerializer());
}
if (AuthenticationRequest == null)
{
AuthenticationRequest = new RestRequest("auth/oauth/v2/token", Method.POST)
{
Credentials = CredentialCache
};
AuthenticationRequest.AddOrUpdateParameter("grant_type", "client_credentials", ParameterType.QueryString);
}
RegisterAuthenticationModule(new Uri("https://api.adp.com/"));
}
/// <summary>
/// Authenticate a request.
/// </summary>
/// <param name="client"></param>
/// <param name="request"></param>
public void Authenticate(IRestClient client, IRestRequest request)
{
//If accessToken is null or expired, get a new one.
if (!HasValidToken())
{
RefreshAccessToken();
}
//request.AddOrUpdateParameter("Authorization", AccessToken, ParameterType.HttpHeader);
//var newCache = new CredentialCache
//{
// {new Uri("https://api.adp.com/"), "Bearer", new NetworkCredential(AccessToken, "") }
//};
var newCache = new CredentialCache();
newCache.Add(new Uri("https://api.adp.com/"), AdpAuthenticationModule.TheAuthenticationType, new NetworkCredential(AccessToken, ""));
request.Credentials = newCache;
//request.AddOrUpdateParameter("Authorization", "Bearer " + AccessToken, ParameterType.HttpHeader);
}
private void RefreshAccessToken()
{
try
{
var response = AuthenticationClient.Execute<AuthorizationResponse>(AuthenticationRequest);
if (response.StatusCode != System.Net.HttpStatusCode.OK)
{
throw new FailedAuthenticationException($"Authentication failed to refresh access token, returned with code {response.StatusCode}. Content: \"{response.Content}\".", null);
}
if (string.IsNullOrWhiteSpace(response.Data.access_token))
{
throw new Exception("Error: response returned during access token refresh gave Status 200 OK, but access_token returned was null or whitespace.");
}
AccessToken = response.Data.access_token;
if (response.Data.expires_in <= 0)
{
throw new Exception("Error: response returned during access token refresh gave Status 200 OK, but expires_in value returned was <=0.");
}
TokenExpiresOn = DateTime.Now.AddSeconds(response.Data.expires_in);
}
catch (FailedAuthenticationException)
{
throw;
}
catch (Exception e)
{
throw new FailedAuthenticationException($"Authentication failed to refresh access token, see inner exception details.", e);
}
}
/// <summary>
/// Returns whether the current access token is valid.
/// </summary>
/// <returns>False if token is null or has 10 or less minutes until expiry; else returns true.</returns>
public bool HasValidToken()
{
return !string.IsNullOrEmpty(AccessToken) && DateTime.Now.CompareTo(TokenExpiresOn.AddMinutes(-10.0)) < 0;
}
private static AdpAuthenticationModule RegisterAuthenticationModule(Uri loginServerUrl)
{
var registeredModules = AuthenticationManager.RegisteredModules;
AdpAuthenticationModule authenticationModule;
while (registeredModules.MoveNext())
{
object current = registeredModules.Current;
if (current is AdpAuthenticationModule)
{
authenticationModule = (AdpAuthenticationModule)current;
if (authenticationModule.LoginServerUrl.Equals(loginServerUrl))
{
return authenticationModule;
}
}
}
authenticationModule = new AdpAuthenticationModule(loginServerUrl);
AuthenticationManager.Register(authenticationModule);
return authenticationModule;
}
}
My Custom Authentication Module:
public class AdpAuthenticationModule : IAuthenticationModule
{
/// <summary>
/// The name of the custom authentication type.
/// </summary>
public string AuthenticationType => TheAuthenticationType;
public static string TheAuthenticationType => "AdpAuthentication";
/// <summary>
/// Returns false, as this IAuthenticationModule cannot pre-authenticate.
/// </summary>
public bool CanPreAuthenticate => false;
private readonly CredentialCache credentialCache = new CredentialCache();
private readonly Uri loginServerUrl;
internal CredentialCache CredentialCache
{
get
{
return credentialCache;
}
}
internal Uri LoginServerUrl
{
get
{
return loginServerUrl;
}
}
internal AdpAuthenticationModule(Uri loginServerUrl)
{
this.loginServerUrl = loginServerUrl ?? throw new ArgumentNullException("AdpAuthenticationModule.loginServerUrl");
}
/// <summary>
/// Builds and returns a <see cref="Authorization"/> object for a request.
/// </summary>
/// <param name="challenge"></param>
/// <param name="request"></param>
/// <param name="credentials"></param>
/// <returns></returns>
public Authorization Authenticate(string challenge, WebRequest request, ICredentials credentials)
{
Authorization result = null;
if (request != null && credentials != null)
{
NetworkCredential creds = credentials.GetCredential(LoginServerUrl, AuthenticationType);
if (creds == null)
{
return null;
}
ICredentialPolicy policy = AuthenticationManager.CredentialPolicy;
if (policy != null && !policy.ShouldSendCredential(LoginServerUrl, request, creds, this))
{
return null;
}
string token = Convert.ToBase64String(Encoding.UTF8.GetBytes(creds.UserName));
result = new Authorization(string.Format("Bearer {0}", token));
}
return result;
}
/// <summary>
/// Returns null, since this IAuthenticationModule cannot pre-authenticate.
/// </summary>
/// <param name="request"></param>
/// <param name="credentials"></param>
/// <returns></returns>
public Authorization PreAuthenticate(WebRequest request, ICredentials credentials)
{
return null;
}
}
Implementation of IAuthenticationModule need to be registered in the AuthenticationManager class from System.Net.
Use the following code :
AuthenticationManager.Register(new AdpAuthenticationModule());

C# code to Update SharePoint list Item using Rest API call

I have to update the list item in sharepoint through Rest Api call,
Requirement:
SharePoint Type: Online
Code for Update: C# Rest API call
Exception: An unhandled exception of type 'System.Net.WebException' occurred in System.dll
Additional information: The remote server returned an error: (403) Forbidden.
public class Class1
{
public static void Main()
{
string result = string.Empty;
Uri uri = new Uri("http://serviceportal.xxx.com/_api/lists/getbytitle('List name')/items(1)");
HttpWebRequest wreq = (HttpWebRequest)WebRequest.Create(uri);
wreq.Credentials = CredentialCache.DefaultNetworkCredentials;
wreq.Method = "POST";
wreq.Accept = "application/json; odata=verbose";
wreq.ContentType = "application/json; odata=verbose";
wreq.Headers.Add("X-HTTP-Method", "MERGE");
wreq.Headers.Add("IF-MATCH", "*");
wreq.Headers.Add("X-RequestDigest", null);
string stringData = "{'__metadata': { 'type': 'SP.Data.TestlistListItem' }, 'Title': 'whatever'}";
wreq.ContentLength = stringData.Length;
StreamWriter writer = new StreamWriter(wreq.GetRequestStream());
writer.Write(stringData);
writer.Flush();
WebResponse wresp = wreq.GetResponse();
using (StreamReader sr = new StreamReader(wresp.GetResponseStream()))
{
result = sr.ReadToEnd();
}
}
}
}
How to over come the above exception and is there any code available for update list item in SharePoint using Rest API call kindly share.
You should pass valid SharePoint Online username and password to get the form digest value and use this digest value in your request header instead of null in your code snippet.
Here is a code sample for your reference:
SPHttpClient.cs and SPHttpClientHandler.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net.Http;
using System.Net.Http.Headers;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace SPORestConsole
{
public class SPHttpClient: HttpClient
{
public SPHttpClient(Uri webUri, string userName, string password) : base(new SPHttpClientHandler(webUri, userName, password))
{
BaseAddress = webUri;
}
/// <summary>
/// Execure request method
/// </summary>
/// <param name="requestUri"></param>
/// <param name="method"></param>
/// <param name="headers"></param>
/// <param name="payload"></param>
/// <returns></returns>
public JObject ExecuteJson<T>(string requestUri, HttpMethod method, IDictionary<string, string> headers, T payload)
{
HttpResponseMessage response;
switch (method.Method)
{
case "POST":
var requestContent = new StringContent(JsonConvert.SerializeObject(payload));
requestContent.Headers.ContentType = MediaTypeHeaderValue.Parse("application/json;odata=verbose");
DefaultRequestHeaders.Add("X-RequestDigest", RequestFormDigest());
if (headers != null)
{
foreach (var header in headers)
{
DefaultRequestHeaders.Add(header.Key, header.Value);
}
}
response = PostAsync(requestUri, requestContent).Result;
break;
case "GET":
response = GetAsync(requestUri).Result;
break;
default:
throw new NotSupportedException(string.Format("Method {0} is not supported", method.Method));
}
response.EnsureSuccessStatusCode();
var responseContent = response.Content.ReadAsStringAsync().Result;
return String.IsNullOrEmpty(responseContent) ? new JObject() : JObject.Parse(responseContent);
}
public JObject ExecuteJson<T>(string requestUri, HttpMethod method, T payload)
{
return ExecuteJson(requestUri, method, null, payload);
}
public JObject ExecuteJson(string requestUri)
{
return ExecuteJson(requestUri, HttpMethod.Get, null, default(string));
}
/// <summary>
/// Request Form Digest
/// </summary>
/// <returns></returns>
public string RequestFormDigest()
{
var endpointUrl = string.Format("{0}/_api/contextinfo", BaseAddress);
var result = this.PostAsync(endpointUrl, new StringContent(string.Empty)).Result;
result.EnsureSuccessStatusCode();
var content = result.Content.ReadAsStringAsync().Result;
var contentJson = JObject.Parse(content);
return contentJson["d"]["GetContextWebInformation"]["FormDigestValue"].ToString();
}
}
}
using System;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Security;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.SharePoint.Client;
namespace SPORestConsole
{
public class SPHttpClientHandler : HttpClientHandler
{
public SPHttpClientHandler(Uri webUri, string userName, string password)
{
CookieContainer = GetAuthCookies(webUri, userName, password);
FormatType = FormatType.JsonVerbose;
}
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
request.Headers.Add("X-FORMS_BASED_AUTH_ACCEPTED", "f");
if (FormatType == FormatType.JsonVerbose)
{
//request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json;odata=verbose"));
request.Headers.Add("Accept", "application/json;odata=verbose");
}
return base.SendAsync(request, cancellationToken);
}
/// <summary>
/// Retrieve SPO Auth Cookies
/// </summary>
/// <param name="webUri"></param>
/// <param name="userName"></param>
/// <param name="password"></param>
/// <returns></returns>
private static CookieContainer GetAuthCookies(Uri webUri, string userName, string password)
{
var securePassword = new SecureString();
foreach (var c in password) { securePassword.AppendChar(c); }
var credentials = new SharePointOnlineCredentials(userName, securePassword);
var authCookie = credentials.GetAuthenticationCookie(webUri);
var cookieContainer = new CookieContainer();
cookieContainer.SetCookies(webUri, authCookie);
return cookieContainer;
}
public FormatType FormatType { get; set; }
}
public enum FormatType
{
JsonVerbose,
Xml
}
}
call update list item action like this:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net.Http;
using System.Net.Http.Headers;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace SPORestConsole
{
class Program
{
static void Main(string[] args)
{
Uri uri = new Uri ("https://tenantname.sharepoint.com/sites/dev/");
using (var client = new SPHttpClient(uri, "username#tanantname.onmicrosoft.com", "yourpassword"))
{
var listTitle = "MyList8";
var itemId = 4;
var itemPayload = new { __metadata = new { type = "SP.Data.MyList8ListItem" }, Title = "updateviaRest" };
var endpointUrl = string.Format("{0}/_api/web/lists/getbytitle('{1}')/items({2})", uri, listTitle, itemId);
var headers = new Dictionary<string, string>();
headers["IF-MATCH"] = "*";
headers["X-HTTP-Method"] = "MERGE";
client.ExecuteJson(endpointUrl, HttpMethod.Post, headers, itemPayload);
Console.WriteLine("Task item has been updated");
}
}
}
}
Reference:
Consume SharePoint Online REST service using .NET

Request.Headers.Authorization is always null even after using [Authorize]

I am currently working on authorizing calls to my API controllers. I am following this tutorial: http://www.c-sharpcorner.com/article/asp-net-mvc5-rest-web-api-authorization/
WebApiController.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
namespace WebApiAuthorization.Controllers {
[Authorize]
public class WebApiController: ApiController {
// GET api/values
public IEnumerable < string > Get() {
return new string[] {
"Hello REST API",
"I am Authorized"
};
}
// GET api/values/5
public string Get(int id) {
return "Hello Authorized API with ID = " + id;
}
// POST api/values
public void Post([FromBody] string value) {}
// PUT api/values/5
public void Put(int id, [FromBody] string value) {}
// DELETE api/values/5
public void Delete(int id) {}
}
}
AuthorizationHeaderHandler.cs
namespace WebApiAuthorization.Helper_Code.Common {
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Security.Claims;
using System.Security.Principal;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Web;
using WebApiAuthorization.Resources.Constants;
/// <summary>
/// Authorization for web API class.
/// </summary>
public class AuthorizationHeaderHandler: DelegatingHandler {#
region Send method.
/// <summary>
/// Send method.
/// </summary>
/// <param name="request">Request parameter</param>
/// <param name="cancellationToken">Cancellation token parameter</param>
/// <returns>Return HTTP response.</returns>
protected override Task < HttpResponseMessage > SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) {
// Initialization.
IEnumerable < string > apiKeyHeaderValues = null;
AuthenticationHeaderValue authorization = request.Headers.Authorization; //This is always null even as I put [Authorize] tag above my controller
string userName = null;
string password = null;
// Verification.
if (request.Headers.TryGetValues(ApiInfo.API_KEY_HEADER, out apiKeyHeaderValues) && !string.IsNullOrEmpty(authorization.Parameter)) {
var apiKeyHeaderValue = apiKeyHeaderValues.First();
// Get the auth token
string authToken = authorization.Parameter;
// Decode the token from BASE64
string decodedToken = Encoding.UTF8.GetString(Convert.FromBase64String(authToken));
// Extract username and password from decoded token
userName = decodedToken.Substring(0, decodedToken.IndexOf(":"));
password = decodedToken.Substring(decodedToken.IndexOf(":") + 1);
// Verification.
if (apiKeyHeaderValue.Equals(ApiInfo.API_KEY_VALUE) && userName.Equals(ApiInfo.USERNAME_VALUE) && password.Equals(ApiInfo.PASSWORD_VALUE)) {
// Setting
var identity = new GenericIdentity(userName);
SetPrincipal(new GenericPrincipal(identity, null));
}
}
// Info.
return base.SendAsync(request, cancellationToken);
}#
endregion# region Set principal method.
/// <summary>
/// Set principal method.
/// </summary>
/// <param name="principal">Principal parameter</param>
private static void SetPrincipal(IPrincipal principal) {
// setting.
Thread.CurrentPrincipal = principal;
// Verification.
if (HttpContext.Current != null) {
// Setting.
HttpContext.Current.User = principal;
}
}#
endregion
}
}
The problem I am facing is in the SendAsync method:
AuthenticationHeaderValue authorization = request.Headers.Authorization; //This is always null even as I put [Authorize] tag above my controller
Doesn't matter if I put [Authorize], [AllowAnonymous], authorization is always null. Looking for some help. Thanks in advance!

Pass JSON data in a http GET request to a REST service

Using the following command:
curl -v -X GET -H "Content-Type: application/json" -d {'"mode":"0"'} http://host.domain.abc.com:23423/api/start-trial-api/
I am able to send the JSON data to web request and get the response back.
How can I do the same in C#?
I am able to POST data to the other service and get the response but don't understand how to send the data to GET request.
I tried searching on google and stackoverflow for the same in C#, but did not find anything.
Sample code - Make sure the request method is set to "GET"
string url = "";
var request = (HttpWebRequest)WebRequest.Create(url);
request.Method = "GET";
request.ContentType = "application/json";
var webResponse = request.GetResponse();
using (var s = webResponse.GetResponseStream())
{
using (TextReader textReader = new StreamReader(s, true))
{
string jsonString = textReader.ReadToEnd();
}
}
Plenty of abstractions here, but hopefully will give a rough guide on how to connect to a service in C#
The Interface
public interface IShopifyAPIGateway
{
HttpResponseMessage Get(string path);
}
Shopify API Gateway, which instatiates HTTPClient()
public sealed class ShopifyAPIGateway : IShopifyAPIGateway
{
/// <summary>
///
/// </summary>
private Identity _identity;
/// <summary>
///
/// </summary>
private HttpClient _httpClient;
/// <summary>
///
/// </summary>
public ShopifyAPIGateway(Identity
identity)
{
_identity = identity;
_httpClient = new HttpClient(ClientHandler());
}
/// <summary>
///
/// </summary>
/// <returns></returns>
public HttpResponseMessage Get(string path)
{
try
{
var response = Connect().GetAsync(path).Result;
return response;
}
catch (CustomHttpResponseException ex)
{
new Email().SendEmail(_identity.ClientName, "Http Response Error - Shopify API Module",
"Http Response Error - Shopify API Module: " + ex.Message,
"error#retain.me");
throw new CustomHttpResponseException(ex.Message);
}
}
/// <summary>
///
/// </summary>
/// <returns></returns>
private HttpClient Connect()
{
try
{
_httpClient.BaseAddress = new Uri(_identity.APIURL);
return _httpClient;
}
catch (CustomHttpRequestException ex)
{
throw new CustomHttpRequestException(ex.Message);
}
}
/// <summary>
///
/// </summary>
/// <param name="userKey"></param>
/// <returns></returns>
private HttpClientHandler ClientHandler()
{
try
{
return new HttpClientHandler()
{
Credentials = new NetworkCredential(_identity.APIKey,
_identity.Password),
PreAuthenticate = true
};
}
catch (CustomClientHandlerException ex)
{
throw new CustomClientHandlerException(ex.Message);
}
}
}
Generic repo to return any object(s) where the response object matches T
public sealed class EntityRepository<T> : IEntityRepository<T>
{
private IShopifyAPIGateway _gateWay;
public T Find(string path)
{
try
{
_gateWay = new ShopifyAPIGateway(_identity);
var json = _gateWay.Get(path).Content.ReadAsStringAsync();
T results = JsonConvert.DeserializeObject<T>(json.Result);
return results;
}
catch (System.Exception ex)
{
throw new ApplicationException(ex.Message);
}
}
}
Usage return type must match the Type your passing and also the Type that's being returned in response.
private IEnumerable<Order> Orders()
{
var entityRepo = new EntityRepository<Order>();
return entityRepo.Find("somedomain/api/orders?mode=0", _identity);
}

Categories

Resources