Failure to getting response from post request in HttpResponseMessage - asp.net-mvc

I read a lot of questions and tested a lot of code but I couldn't solve my problem.
I want call rest API (that write with php code) in asp controller.
I tested my web service with postman app and get responds correctly from web service . But I can't get the right answer through asp request.
My problem: I get status code 200 for response(in asp controller) But the instructions on the web service are not executed(for example: don't register user). Where can I find the problem and get the data in the answer?
public async Task registerInShop()
{
try
{
ShopUserModel model = new ShopUserModel()
{
user_login = "ff",
user_pass = "v12315",
user_nicename = "",
user_url = "",
user_registered = "",
user_activation_key = "",
user_status = 0,
display_name = "ff",
};
JsonResult json = Json(model, JsonRequestBehavior.AllowGet);
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("domainurl/");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;
HttpResponseMessage response = await client.PostAsJsonAsync("shopktphp/register.php", json.Data);
response.EnsureSuccessStatusCode();
if (response.IsSuccessStatusCode)
{ // Get the URI of the created resource.
Uri returnUrl = response.Headers.Location;
var res = response.Content;
Console.WriteLine(returnUrl);
}
}
}
catch (Exception ex)
{
Elmah.ErrorLog.GetDefault(null).Log(new Elmah.Error(ex));
}
}

I successful finding answer of my question. I change only URI of base address and set by this: "domainurl/shopktphp/"
and set Post json async by "register.php"
client.BaseAddress = new Uri("domainurl/shopktphp/");
HttpResponseMessage response = await client.PostAsJsonAsync("register.php", json.Data);

Related

How to add JwT token in request header ASP.Net MVC Core 6

I have just started to use Asp.Net Core and I managed to create a mvc project. In This project I have created an API and it is secured with token based authorization.I have also used identity framework for user auhentication. Now I want to consume this API to perform CRUD operations with passing token but have no clear idea how to do that. After searching similar questions what I have tried is generate the token using user credentials (username, password) when user successfully logged in or registered and attach the generated token to header and as far as I know it will be passed through each subsequent request.
First I tried creating a method to call to generate the token after success login or registration. This includes in same controller which used for login and registration.
Token generate method
public string GenerateAuthToken(ApplicationUser applicationUser)
{
var tokenHandler = new JwtSecurityTokenHandler();
var key = Encoding.ASCII.GetBytes(_configuration.GetSection("JWT")["TokenSignInKey"]);
var tokenDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(new Claim[] {
new Claim(type:JwtRegisteredClaimNames.Sub, applicationUser.Id),
new Claim(type:JwtRegisteredClaimNames.Email, applicationUser.Email),
new Claim(type:JwtRegisteredClaimNames.Iat,
value:DateTime.Now.ToUniversalTime().ToString())
}),
Expires = DateTime.UtcNow.AddHours(1),
SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key),
SecurityAlgorithms.HmacSha256Signature)
};
var token = tokenHandler.CreateToken(tokenDescriptor);
var stringToken = tokenHandler.WriteToken(token);
return stringToken;
}
I call this after success user login and register,
public async Task<IActionResult> Register(RegisterViewModel registerViewModel)
{
if (ModelState.IsValid)
{
var user = new ApplicationUser { UserName = registerViewModel.Username,
Email = registerViewModel.Email};
var result = await _userManager.CreateAsync(user, registerViewModel.Password);
if (result.Succeeded)
{
await _signInManager.SignInAsync(user, isPersistent: false);
var token = GenerateAuthToken(user);
var httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.Authorization = new
AuthenticationHeaderValue("bearer", token);
return RedirectToAction("Index", "Home");
}
ModelState.AddModelError("", "User Registration Failed");
}
return View(registerViewModel);
}
When this executed, the token is successfully generated but does not attach the token. I do not know if I am doing any wrong here. But I found someone facing the same issue but has tried different way to achieve this. I think it is the correct way but not sure. Instead of generate the token on success login, have to generate it each api call. According to this solution I created another controller and action to generate the token.
public async Task<IActionResult> GetToken([FromBody] AuthViewModel authViewModel)
{
var user = _context.Users.FirstOrDefault(u => u.Email == authViewModel.Email);
if (user != null)
{
var signInResult = await _signInManager.CheckPasswordSignInAsync(user,
authViewModel.Password, false);
if (signInResult.Succeeded)
{
var tokenHandler = new JwtSecurityTokenHandler();
var key = Encoding.ASCII.GetBytes(_configuration.GetSection("JWT")
["TokenSignInKey"]);
var tokenDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(new Claim[] {
new Claim(type:JwtRegisteredClaimNames.Sub,authViewModel.Email),
new Claim(type:JwtRegisteredClaimNames.Email,
authViewModel.Email),
new Claim(type:JwtRegisteredClaimNames.Iat,
value:DateTime.Now.ToUniversalTime().ToString())
}),
Expires = DateTime.UtcNow.AddHours(1),
SigningCredentials = new SigningCredentials(new
SymmetricSecurityKey(key),
SecurityAlgorithms.HmacSha256Signature)
};
var token = tokenHandler.CreateToken(tokenDescriptor);
var stringToken = tokenHandler.WriteToken(token);
return Ok(new { Token = stringToken });
}
return BadRequest("Invalid User");
}}
AuthViewModel
public class AuthViewModel
{
[Required]
public string Email { get; set; }
[Required]
public string Password { get; set; }
}
I added authViewModel to accept logged user credentials since I don't want add them manually, Then I have created another controller to perform the CRUD same as the above mentioned link Please note that I followed the solution mentioned below that page.
private async Task<string> CreateToken()
{
var user = await _userManager.GetUserAsync(User);
var request = new HttpRequestMessage(HttpMethod.Post, "http://localhost:7015/Auth");
request.Content = JsonContent.Create(new AuthViewModel{
Email = user.Email, Password = user.PasswordHash
});
var client = _clientFactory.CreateClient();
HttpResponseMessage response = await client.SendAsync(request);
var token = await response.Content.ReadAsStringAsync();
HttpContext.Session.SetString("JwToken", token);
return token;
}
request.Content I added to match my solution since token should be generated using user credentials. But I have no idea how to pass the logged in user's credentials with the request. This does not work. It is not possible to access the user password.
This is how I called the token generate action to perform CRUD. And I use JQuery Ajax to call the GetAllSales endpoint.
public async Task<IActionResult> GetAllSales()
{
string token = null;
var strToken = HttpContext.Session.GetString("JwToken");
if (string.IsNullOrWhiteSpace(strToken))
{
token = await CreateToken();
}
else
{
token = strToken;
}
List<Sale> sales = new List<Sale>();
var client = _clientFactory.CreateClient();
var request = new HttpRequestMessage(HttpMethod.Get,
"http://localhost:7015/api/Sales");
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);
HttpResponseMessage response = await client.SendAsync(request,
HttpCompletionOption.ResponseHeadersRead);
if (response.StatusCode == System.Net.HttpStatusCode.OK)
{
var apiString = await response.Content.ReadAsStringAsync();
sales = JsonConvert.DeserializeObject<List<Sale>>(apiString);
}
Ok(sales);
}
This does not work. An exception throws
'System.InvalidOperationException: Unable to resolve service for type 'System.Net.Http.IHttpClientFactory' while attempting to activate '_7_ElevenRetail.Controllers.AccessApiController'.
at Microsoft.Extensions.DependencyInjection.ActivatorUtilities.GetService(IServiceProvider sp, Type type, Type requiredBy, Boolean isDefaultParameterRequired)'
Please suggest me and show me how to achieve this correctly. I am expecting all of your help. Thank you.
System.InvalidOperationException: Unable to resolve service for type 'System.Net.Http.IHttpClientFactory' while attempting to activate '_7_ElevenRetail.Controllers.AccessApiController'
This issue means you inject IHttpClientFactory in AccessApiController without registering the service in Program.cs.
Register IHttpClientFactory by calling AddHttpClient in Program.cs:
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddHttpClient();

How to authorize in Azure Active Directory without using dialog?

My application shows dashboard of my power bi account for all users, I am authorizing the Azure Active Directory through a dialog to get an access token. Can I hard code my credentials and get access token without using the authorization dialog.
Code. It works but it is using the authorization dialog.
var #params = new NameValueCollection
{
{"response_type", "code"},
{"client_id", Properties.Settings.Default.ClientID},
{"resource", "https://analysis.windows.net/powerbi/api"},
{"redirect_uri", "http://localhost:13526/Redirect"}
};
var queryString = HttpUtility.ParseQueryString(string.Empty);
queryString.Add(#params);
string authorityUri = "https://login.windows.net/common/oauth2/authorize/";
var authUri = String.Format("{0}?{1}", authorityUri, queryString);
Response.Redirect(authUri);
Redirect.aspx
string redirectUri = "http://localhost:13526/Redirect";
string authorityUri = "https://login.windows.net/common/oauth2/authorize/";
string code = Request.Params.GetValues(0)[0];
TokenCache TC = new TokenCache();
AuthenticationContext AC = new AuthenticationContext(authorityUri, TC);
ClientCredential cc = new ClientCredential
(Properties.Settings.Default.ClientID,
Properties.Settings.Default.ClientSecret);
AuthenticationResult AR = AC.AcquireTokenByAuthorizationCode(code, new Uri(redirectUri), cc);
Session[_Default.authResultString] = AR;
Response.Redirect("/Default.aspx");
Default.aspx
string responseContent = string.Empty;
System.Net.WebRequest request = System.Net.WebRequest.Create(String.Format("{0}dashboards", baseUri)) as System.Net.HttpWebRequest;
request.Method = "GET";
request.ContentLength = 0;
request.Headers.Add("Authorization", String.Format("Bearer {0}", authResult.AccessToken));
using (var response = request.GetResponse() as System.Net.HttpWebResponse)
{
using (var reader = new System.IO.StreamReader(response.GetResponseStream()))
{
responseContent = reader.ReadToEnd();
PBIDashboards PBIDashboards = JsonConvert.DeserializeObject<PBIDashboards>(responseContent);
}
}
I did this once without using ADAL. For Power BI as well, since they don't offer application permissions, only delegated.
Note: This method won't work if the user has MFA enabled, their password has expired etc.
In general you'll want to use interactive flows.
You can even have a bootstrapping process where the user logs in interactively and you store the refresh token received.
That refresh token can then be used in the background as long as it works.
What you need to is call the AAD token endpoint with grant_type=password. You will specify the username and password, as well as the client id, client secret and resource URI in form parameters.
Here is the function I wrote:
private async Task<string> GetAccessToken()
{
string tokenEndpointUri = Authority + "oauth2/token";
var content = new FormUrlEncodedContent(new []
{
new KeyValuePair<string, string>("grant_type", "password"),
new KeyValuePair<string, string>("username", Username),
new KeyValuePair<string, string>("password", Password),
new KeyValuePair<string, string>("client_id", ClientId),
new KeyValuePair<string, string>("client_secret", ClientSecret),
new KeyValuePair<string, string>("resource", PowerBiResourceUri)
}
);
using (var client = new HttpClient())
{
HttpResponseMessage res = await client.PostAsync(tokenEndpointUri, content);
string json = await res.Content.ReadAsStringAsync();
AzureAdTokenResponse tokenRes = JsonConvert.DeserializeObject<AzureAdTokenResponse>(json);
return tokenRes.AccessToken;
}
}
Authority here is https://login.microsoftonline.com/tenant-id/. Here is the response class I'm using:
class AzureAdTokenResponse
{
[JsonProperty("access_token")]
public string AccessToken { get; set; }
}
I hope using UserCreadential you have give username and password of azure subscription and you can get AccessToken and call your api. i hope it should helps you.
string ResourceUrl="https://analysis.windows.net/powerbi/api";
string ClientId=Properties.Settings.Default.ClientID;//as per your code
AuthenticationContext authenticationContext = new AuthenticationContext(Constants.AuthString, false);
UserCredential csr = new UserCredential("your-username", "password");
AuthenticationResult authenticationResult = authenticationContext.AcquireToken(ResourceUrl,ClientId, usr);
string token = authenticationResult.AccessToken;

InvalidAuthenticationToken when trying to invoke Microsoft Graph client

I'm following a sample provided at the Microsoft Graph repository on github. In it, it describes using the DelegateAuthenticationProvider which needs an access token.
Marc LaFleur's primer on auth flow specified a way to get the access token which I combined with guidance on making service-service authentication work.
Even though I receive what appears to be a valid access token, when I issue the command via the graph client, I get a ServiceException from Microsoft Graph stating,
"{
Code: InvalidAuthenticationToken
Message: Access token validation failure.
Inner error
}"
I haven't seen any other inner error.
What am I doing incorrectly?
This is the code I've come up:
var clientId = "[app-guid]";
var clientSecret = "[secret-from-app-dashboard]";
var resource = "[app-guid]";
var baseUrl = "https://login.microsoftonline.com";
var loginUrl = "/[tenant guid]/oauth2/token";
using (var client = new HttpClient())
{
client.BaseAddress = new Uri(baseUrl);
var content = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("grant_type", "client_credentials"),
new KeyValuePair<string, string>("client_id", clientId),
new KeyValuePair<string, string>("client_secret", clientSecret),
new KeyValuePair<string, string>("resource", resource)
});
var result = client.PostAsync(loginUrl, content).Result;
string resultContent = result.Content.ReadAsStringAsync().Result;
var json = JObject.Parse(resultContent);
accessToken = (string)json["access_token"];
}
var header = new AuthenticationHeaderValue("Bearer", accessToken);
var graphserviceClient = new GraphServiceClient(
new DelegateAuthenticationProvider(
(requestMessage) =>
{
requestMessage.Headers.Authorization = header;
return Task.FromResult(0);
}));
try
{
var users = await graphserviceClient.Users.Request().GetAsync();
var user = users.First();
}
catch (Microsoft.Graph.ServiceException servex)
{
Console.WriteLine(servex);
}
You set your resource to point to your website, but it should point to the external web resource you wish to access. Try this:
var resource = "https://graph.microsoft.com/";

While Calling Web.api getting 'Method not allowed' error'

While consuming the web.Api i am getting method not allowed(405). i followed all step but issue is still there. But when I test through soapUi it works well. Please help
Web.Api Declaration:
[Route("ForgotPassword")]
[AcceptVerbs( "POST")]
public ForgotPasswordResponse ForgotPassword(string emailId)
{
AccountInfo accountInfo = _manager.GetUserByEmailId(emailId);
if (accountInfo == null)
return new ForgotPasswordResponse
{
Response = "error",
Message = "Email address not found"
};
return new ForgotPasswordResponse
{
Response = "success",
Message = "password reset link set to registered email id"
};
}
Consuming Service call:
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("http://100.7.11.76");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var response12 = client.GetAsync("test.Api/api/account/ForgotPassword?EmailId=" + email + "").Result;
if (response12.IsSuccessStatusCode)
{
string responseString = response12.Content.ReadAsStringAsync().Result;
}
}
Your WebAPI controller ForgotPasswordResponse accepts the verb "POST" and your WebAPI client is invoking it as GET. Hence you get 406: Method not allowed response. Either make your controller accept GET verb or invoke the WebAPI using PostAsJsonAsync method instead of GetAsync.
Try to use Authentication Filters [AllowAnonymous]
[AllowAnonymous]
[Route("ForgotPassword")]
[AcceptVerbs( "POST")]
public ForgotPasswordResponse ForgotPassword(string emailId)
{
AccountInfo accountInfo = _manager.GetUserByEmailId(emailId);
if (accountInfo == null)
return new ForgotPasswordResponse
{
Response = "error",
Message = "Email address not found"
};
return new ForgotPasswordResponse
{
Response = "success",
Message = "password reset link set to registered email id"
};
}
Change the Route attribute to [Route("api/account/ForgotPassword")], change from POST to GET and test your method from a REST client like PostMan first and then use it in your application.

Trying to read response from Web API call

I'm trying to read my employees list from a Web API call but getting errors.
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("http://myApiUrl");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage response = await client.GetAsync("api/hr/employees");
if (response.IsSuccessStatusCode)
{
List<Employee> employees = response.Content.ReadAsAsync(IEnumerable<Employee>).Result;
}
}
The error I'm currently getting is:
System.Net.Http.HttpContent does not contain a definition for ReadAsAsync...
What am I doing wrong?
ReadAsAsync is not a method on the HttpClient class. If you want to read the data and cast it to an object you can use:
HttpResponseMessage response = await client.GetAsync("api/hr/employees");
if (response.IsSuccessStatusCode)
{
var result= await response.Content.ReadAsStringAsync();
List<Employee> employees = JsonConvert.DeserializeObject<Employee>(result);
}
Try
List<Employee> employees = response.Content.ReadAsAsync<IEnumerable<Employee>>().Result;

Resources