*******in server**********
config.cs
public class Config
{
private readonly IConfiguration _configuration;
public Config(IConfiguration configuration)
{
_configuration = configuration;
}
// scopes define the resources in your system
public IEnumerable<IdentityResource> GetIdentityResources()
{
return new List<IdentityResource>
{
new IdentityResources.OpenId(),
new IdentityResources.Profile(),
};
}
public IEnumerable<ApiResource> GetApiResources(string companyCode, bool isTest)
{
return new List<ApiResource>
{
new ApiResource(){
Name = "APIServiceHUB",
ApiSecrets =
{
new Secret(GetSecret(companyCode, isTest).Sha256())
},
Scopes =
{
new Scope()
{
Name = "APIServiceHUB",
DisplayName = "APIService HUB",
}
}
},
new ApiResource("projects-api", "Projects API")
};
}
// clients want to access resources (aka scopes)
public IEnumerable<Client> GetClients(string companyCode, bool isTest)
{
var optionsBuilder = new DbContextOptionsBuilder<DickerDataContext>();
DickerDataContext dickerDataContext = new DickerDataContext(optionsBuilder.Options);
// client credentials client
return new List<Client>
{
new Client
{
ClientId = "client",
AllowedGrantTypes = GrantTypes.HybridAndClientCredentials,
ClientName = "APIService HUB",
RedirectUris = new List<string>{ "http://dev-webservices.dickerdata.com.au/signin-oidc" },
RequireConsent = false,
AllowOfflineAccess = true,
//Access token life time is 14400 seconds (4 hours)
AccessTokenLifetime = 14400,
//Identity token life time is 14400 seconds (4 hours)
IdentityTokenLifetime = 14400,
ClientSecrets =
{
new Secret(GetSecret(companyCode, isTest).Sha256())
},
AllowedScopes =
{
"APIServiceHUB"
}
},
// OpenID Connect implicit flow client (MVC)
new Client
{
ClientId = "mvc",
ClientName = "MVC Client",
AllowedGrantTypes = GrantTypes.Implicit,
RedirectUris = { "http://localhost:60948/signin-oidc" },
PostLogoutRedirectUris = { "http://localhost:60948/signout-callback-oidc" },
AllowedScopes =
{
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile
}
}
};
}
private string GetSecret(string companyCode, bool isTest)
{
var optionsBuilder = new DbContextOptionsBuilder<DickerDataContext>();
optionsBuilder.UseSqlServer(_configuration.GetConnectionString("DickerDataConString"));
DickerDataContext dickerDataContext = new DickerDataContext(optionsBuilder.Options);
string secret = dickerDataContext.SiteConfig.Where(x => x.Vendor == "SERVICEHUB" && x.CompanyCode == companyCode && (x.IsTest ?? false) == isTest).FirstOrDefault().Value;
return secret;
}
}
in startup.cs
services.AddIdentityServer()
.AddDeveloperSigningCredential()
.AddInMemoryApiResources(Config.GetApiResources())
.AddInMemoryClients(Config.GetClients());
in Service file
public TokenModelResponse GetToken(string clientId, string secret)
{
string url = _dBManager.GetURL(APIList.SH_DD_Token);
TokenModel inputModel = new TokenModel()
{
ClientId = clientId,
Secret = secret
};
var token = ServiceHubJsonExtractor.GetJsonResult<TokenModelResponse>("http://localhost:51678/api/Token/Authenticate", WebMethods.GET, inputModel, null, null);
return token;
}
public class ServiceHubJsonExtractor
{
public static T GetJsonResult<T>(string baseUrl, WebMethods method,
dynamic queryParameters = null,
dynamic bodyContent = null,
dynamic token = null,
string contentType = "application/json") where T : new()
{
string url = string.Empty;
if (queryParameters != null)
{
url = BuildUrl(baseUrl, queryParameters);
}
else
{
url = baseUrl;
}
var request = (HttpWebRequest)HttpWebRequest.Create(url);
request.Accept = "application/json";
request.Method = method.ToString();
request.ContentType = contentType;
if (token != null)
{
request.Headers.Add("Authorization", $"{token.Token_Type} {token.Access_Token}");
}
var settings = new JsonSerializerSettings
{
PreserveReferencesHandling = PreserveReferencesHandling.Objects,
Converters = { new JsonExtractor.StringOrArrayConverter() },
Error = (sender, args) =>
{
if (System.Diagnostics.Debugger.IsAttached)
{
System.Diagnostics.Debug.Write(args.CurrentObject.ToString());
System.Diagnostics.Debugger.Break();
}
}
};
try
{
if (bodyContent != null)
{
string contentString = string.Empty;
if (bodyContent is String)
{
contentString = bodyContent;
}
else
{
contentString = JsonConvert.SerializeObject(bodyContent);
}
using (var writer = new StreamWriter(request.GetRequestStream()))
{
writer.Write(contentString);
}
}
var response = request.GetResponse();
using (var reader = new StreamReader(response.GetResponseStream()))
{
var responseContent = reader.ReadToEnd();
var result = new T();
try
{
if (!string.IsNullOrWhiteSpace(responseContent))
result = JsonConvert.DeserializeObject<T>(responseContent, settings);
}
catch (Exception ex)
{
throw ex;
}
return result;
}
}
catch (WebException webException)
{
string error = string.Empty;
try
{
var errroResponse = new StreamReader(webException.Response.GetResponseStream());
error = errroResponse.ReadToEnd();
}
catch
{
throw webException;
}
throw new Exception(error);
}
}
private static string BuildUrl(string baseUrl, dynamic queryParameters)
{
string url = string.Empty, parameterList = string.Empty;
if (queryParameters != null)
{
try
{
// the parameters could be dictionary or list
Type type = queryParameters.GetType();
if (type.Name == "Dictionary`2" || type.Name == "List`1") // dictionary/list
{
foreach (KeyValuePair<string, string> param in queryParameters)
{
if (parameterList.Length > 0) parameterList += "&";
parameterList += string.Format("{0}={1}", param.Key, param.Value);
}
}
else // class with properties
{
foreach (PropertyInfo propertyInfo in type.GetProperties())
{
if (propertyInfo.CanRead)
{
if (parameterList.Length > 0) parameterList += "&";
parameterList += string.Format("{0}={1}", propertyInfo.Name, propertyInfo.GetValue(queryParameters, null));
}
}
}
}
catch (JsonException jex)
{
throw jex;
}
catch (Exception ex)
{
throw ex;
}
}
if (!string.IsNullOrWhiteSpace(parameterList))
{
url = string.Format("{0}?{1}", baseUrl, parameterList);
}
else
{
url = baseUrl;
}
return url;
}
}
*******in api project********
*******Fetch token from other server:
private async Task<TokenModelResponse> FetchToken(string clientId, string secret)
{
var disco = await DiscoveryClient.GetAsync("http://localhost:60948");
//var response = new AuthorizeResponse("http://localhost:60948");
if (disco.IsError)
{
Console.WriteLine(disco.Error);
return new TokenModelResponse { Message = "Fail to get token from server" };
}
// request token
var tokenClient = new TokenClient(disco.TokenEndpoint, clientId, secret);
var tokenResponse = await tokenClient.RequestClientCredentialsAsync("APIServiceHUB");
if (tokenResponse.IsError)
{
Console.WriteLine(tokenResponse.Error);
return new TokenModelResponse { Message = "Fail to get token from server" };
}
var introspectionClient = new IntrospectionClient(
disco.IntrospectionEndpoint,
"APIServiceHUB",
secret);
var introspectionResponse = await introspectionClient.SendAsync(
new IntrospectionRequest { Token = tokenResponse.AccessToken });
if (introspectionResponse.IsError)
{
Console.WriteLine(introspectionResponse.Error);
return new TokenModelResponse { Message = "Fail to get token from server" };
}
TokenModelResponse tokenModelResponse = new TokenModelResponse();
tokenModelResponse.Access_Token = tokenResponse.AccessToken;
tokenModelResponse.Token_Type = tokenResponse.TokenType;
tokenModelResponse.Expires_In = tokenResponse.ExpiresIn;
tokenModelResponse.Issured = ToDateTimeFromEpoch(long.Parse(introspectionResponse.Json.GetValue("nbf").ToString())).ToString("r");
tokenModelResponse.Expires = ToDateTimeFromEpoch(long.Parse(introspectionResponse.Json.GetValue("exp").ToString())).ToString("r");
tokenModelResponse.Message = "Successfully get token";
return tokenModelResponse;
}
private DateTime ToDateTimeFromEpoch(long intDate)
{
var timeInTicks = intDate * TimeSpan.TicksPerSecond;
return new DateTime(1970, 1, 1, 10, 0, 0, 0, DateTimeKind.Local).AddTicks(timeInTicks);
}
[HttpGet]
public async Task<IHttpActionResult> Authenticate() // controller method to get token
{
var loginResponse = new LoginResponse { };
//LoginRequest loginrequest = new LoginRequest { };
//loginrequest.Username = login.Username.ToLower();
//loginrequest.Password = login.Password;
IHttpActionResult response;
HttpResponseMessage responseMsg = new HttpResponseMessage();
bool isUsernamePasswordValid = true;
//if(login != null)
//isUsernamePasswordValid=loginrequest.Password=="admin" ? true:false;
// if credentials are valid
if (isUsernamePasswordValid)
{
string token = await FetchToken();
//return the token
return Ok(token);
}
else
{
// if credentials are not valid send unauthorized status code in response
loginResponse.responseMsg.StatusCode = HttpStatusCode.Unauthorized;
response = ResponseMessage(loginResponse.responseMsg);
return response;
}
}
*******login response model
public class TokenModel
{
public string ClientId { get; set; }
public string Secret { get; set; }
}
public class LoginRequest
{
public string Username { get; set; }
public string Password { get; set; }
}
public class LoginResponse
{
public LoginResponse()
{
this.Token = "";
this.responseMsg = new HttpResponseMessage() { StatusCode = System.Net.HttpStatusCode.Unauthorized };
}
public string Token { get; set; }
public HttpResponseMessage responseMsg { get; set; }
}
public class TokenModelResponse
{
public string Access_Token { get; set; }
public string Token_Type { get; set; }
public long Expires_In { get; set; }
public string UserName { get; set; }
public string FullName { get; set; }
public string Logo { get; set; }
public string ChannelPortalId { get; set; }
public string Permissions { get; set; }
public string WorkflowUserGroup { get; set; }
public string LogonId { get; set; }
public string Issured { get; set; }
public string Expires { get; set; }
}
*******validate token:
using IdentityModel;
using IdentityModel.Client;
using Microsoft.IdentityModel.Protocols;
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
using Microsoft.IdentityModel.Tokens;
using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Threading;
using System.Threading.Tasks;
using System.Web;
internal class TokenValidationHandler : DelegatingHandler
{
const string auth0Domain = "http://localhost:50191/";
private static bool TryRetrieveToken(HttpRequestMessage request, out string token)
{
token = null;
IEnumerable<string> authzHeaders;
if (!request.Headers.TryGetValues("Authorization", out authzHeaders) || authzHeaders.Count() > 1)
{
return false;
}
var bearerToken = authzHeaders.ElementAt(0);
token = bearerToken.StartsWith("Bearer ") ? bearerToken.Substring(7) : bearerToken;
return true;
}
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
HttpStatusCode statusCode;
string token;
//determine whether a jwt exists or not
if (!TryRetrieveToken(request, out token))
{
statusCode = HttpStatusCode.Unauthorized;
//allow requests with no token - whether a action method needs an authentication can be set with the claimsauthorization attribute
return await base.SendAsync(request, cancellationToken);
}
try
{
//const string sec = "401b09eab3c013d4ca54922bb802bec8fd5318192b0a75f201d8b3727429090fb337591abd3e44453b954555b7a0812e1081c39b740293f765eae731f5a65ed1";
//var now = DateTime.UtcNow;
//var securityKey = new SymmetricSecurityKey(System.Text.Encoding.Default.GetBytes(sec));
SecurityToken securityToken;
JwtSecurityTokenHandler handler = new JwtSecurityTokenHandler();
handler.InboundClaimTypeMap.Clear();
var disco = await DiscoveryClient.GetAsync("http://localhost:60948");
var keylist = new List<SecurityKey>();
foreach (var webKey in disco.KeySet.Keys)
{
var exp = Base64Url.Decode(webKey.E);
var mod = Base64Url.Decode(webKey.N);
var key = new RsaSecurityKey(new RSAParameters() { Modulus = mod, Exponent = exp });
keylist.Add(key);
}
TokenValidationParameters validationParameters = new TokenValidationParameters()
{
ValidAudience = "http://localhost:60948/resources",
ValidIssuer = "http://localhost:60948",
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
LifetimeValidator = this.LifetimeValidator,
IssuerSigningKeys = keylist
};
//extract and assign the user of the jwt
Thread.CurrentPrincipal = handler.ValidateToken(token, validationParameters, out securityToken);
HttpContext.Current.User = handler.ValidateToken(token, validationParameters, out securityToken);
return await base.SendAsync(request, cancellationToken);
}
catch (SecurityTokenValidationException e)
{
statusCode = HttpStatusCode.Unauthorized;
}
catch (Exception ex)
{
statusCode = HttpStatusCode.InternalServerError;
}
return await Task<HttpResponseMessage>.Factory.StartNew(() => new HttpResponseMessage(statusCode) { });
}
public bool LifetimeValidator(DateTime? notBefore, DateTime? expires, SecurityToken securityToken, TokenValidationParameters validationParameters)
{
if (expires != null)
{
if (DateTime.UtcNow < expires) return true;
}
return false;
}
private async Task<OpenIdConnectConfiguration> GetSigningKeys()
{
IConfigurationManager<OpenIdConnectConfiguration> configurationManager = new ConfigurationManager<OpenIdConnectConfiguration>($"{auth0Domain}.well-known/openid-configuration", new OpenIdConnectConfigurationRetriever());
OpenIdConnectConfiguration openIdConfig = await configurationManager.GetConfigurationAsync(CancellationToken.None);
return openIdConfig;
}
}
********API controller
add [Authorize] to controller class
_________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________
*******create token and validate************
private string createToken(string username)
{
//Set issued at date
DateTime issuedAt = DateTime.UtcNow;
//set the time when it expires
DateTime expires = DateTime.UtcNow.AddDays(7);
//http://stackoverflow.com/questions/18223868/how-to-encrypt-jwt-security-token
var tokenHandler = new JwtSecurityTokenHandler();
//create a identity and add claims to the user which we want to log in
ClaimsIdentity claimsIdentity = new ClaimsIdentity(new[]
{
new Claim(ClaimTypes.Name, username)
});
const string sec = "401b09eab3c013d4ca54922bb802bec8fd5318192b0a75f201d8b3727429090fb337591abd3e44453b954555b7a0812e1081c39b740293f765eae731f5a65ed1";
var now = DateTime.UtcNow;
var securityKey = new Microsoft.IdentityModel.Tokens.SymmetricSecurityKey(System.Text.Encoding.Default.GetBytes(sec));
var signingCredentials = new Microsoft.IdentityModel.Tokens.SigningCredentials(securityKey, Microsoft.IdentityModel.Tokens.SecurityAlgorithms.HmacSha256Signature);
//create the jwt
var token =
(JwtSecurityToken)
tokenHandler.CreateJwtSecurityToken(issuer: "http://localhost:60948", audience: "http://localhost:60948/resources",
subject: claimsIdentity, notBefore: issuedAt, expires: expires, signingCredentials: signingCredentials);
var tokenString = tokenHandler.WriteToken(token);
return tokenString;
}
internal class TokenValidationHandler : DelegatingHandler
{
private static bool TryRetrieveToken(HttpRequestMessage request, out string token)
{
token = null;
IEnumerable<string> authzHeaders;
if (!request.Headers.TryGetValues("Authorization", out authzHeaders) || authzHeaders.Count() > 1)
{
return false;
}
var bearerToken = authzHeaders.ElementAt(0);
token = bearerToken.StartsWith("Bearer ") ? bearerToken.Substring(7) : bearerToken;
return true;
}
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
HttpStatusCode statusCode;
string token;
//determine whether a jwt exists or not
if (!TryRetrieveToken(request, out token))
{
statusCode = HttpStatusCode.Unauthorized;
//allow requests with no token - whether a action method needs an authentication can be set with the claimsauthorization attribute
return base.SendAsync(request, cancellationToken);
}
try
{
const string sec = "401b09eab3c013d4ca54922bb802bec8fd5318192b0a75f201d8b3727429090fb337591abd3e44453b954555b7a0812e1081c39b740293f765eae731f5a65ed1";
var now = DateTime.UtcNow;
var securityKey = new SymmetricSecurityKey(System.Text.Encoding.Default.GetBytes(sec));
SecurityToken securityToken;
JwtSecurityTokenHandler handler = new JwtSecurityTokenHandler();
TokenValidationParameters validationParameters = new TokenValidationParameters()
{
ValidAudience = "http://localhost:50191",
ValidIssuer = "http://localhost:5001",
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
LifetimeValidator = this.LifetimeValidator,
IssuerSigningKey = securityKey
};
//extract and assign the user of the jwt
Thread.CurrentPrincipal = handler.ValidateToken(token, validationParameters, out securityToken);
HttpContext.Current.User = handler.ValidateToken(token, validationParameters, out securityToken);
return base.SendAsync(request, cancellationToken);
}
catch (SecurityTokenValidationException e)
{
statusCode = HttpStatusCode.Unauthorized;
}
catch (Exception ex)
{
statusCode = HttpStatusCode.InternalServerError;
}
return Task<HttpResponseMessage>.Factory.StartNew(() => new HttpResponseMessage(statusCode){ });
}
public bool LifetimeValidator(DateTime? notBefore, DateTime? expires, SecurityToken securityToken, TokenValidationParameters validationParameters)
{
if (expires != null)
{
if (DateTime.UtcNow < expires) return true;
}
return false;
}
}