I have an ASP.Net Web API that is posted to from an external source. The values that are posted to the web api are used to determine the user's rights on our website. So the web api then passes the result object of my business logic as a bunch of cookies to our asp landing page. The problem is that the cookies are no longer available in the web page that the web api routed the response to.
Here is web api:
[HttpPost]
public HttpResponseMessage Reports(ReportRequest reportRequest)
{
if (reportRequest != null)
{
var reportAccess = new SwitchBL().CheckUserAccess(reportRequest);
var response = Request.CreateResponse(HttpStatusCode.Moved);
response.Headers.Location = new Uri(BaseUrl() + "/menu.aspx");
var json = JsonConvert.SerializeObject(reportAccess);
Dictionary<string, string> biscuitTin = JsonConvert.DeserializeObject<Dictionary<string, string>>(json);
foreach (var biscuit in biscuitTin)
{
var cookie =
new CookieHeaderValue(biscuit.Key, biscuit.Value ?? "")
{
Expires = DateTimeOffset.Now.AddDays(1),
Domain = Request.RequestUri.Host == "localhost" ? null : Request.RequestUri.Host,
HttpOnly = true
};
//cookierJar.Add(cookie);
response.Headers.AddCookies(new CookieHeaderValue[] {cookie} );
}
return response;
}
return Request.CreateResponse(HttpStatusCode.BadRequest);
}
And so far my very simple aspx page always shows count = 0:
public partial class menu : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
var cookieCount = Request.Cookies.Count;
}
}
The web api and aspx pages are in the same project thus hosted in one site. I do not want to use session variables and do not want to pass values in querystrings. Is there another way of passing data to the routed page from the web api or am I missing something here?
BTW, if I post to the api using Postman, the cookies are visible in the response header of the web api, so cookies are created. If I post using another web page, using Fiddler, I can see the cookies in the response of the api but then there are no cookies in the (receiving) asp page.
UPDATE
Thanks to the answer of Kai, I can now get the cookies in my route asp page as set in response.Headers.Location. I have a breakpoint in that page so I know it is being hit and cookie count is now as expected. However, the browser does not render the routed page. It remains on the original posting page. Here is the code I'm using in my post emulator page to call the web api:
protected void Page_Load(object sender, EventArgs e)
{
}
protected async void DoIt_OnClick(object sender, EventArgs e)
{
var reportRequest = new ReportRequest();
reportRequest.EmailAddress = Email.Text;
reportRequest.UserNumber = UserCode.Text;
reportRequest.MobileNumber = MobileNumber.Text;
reportRequest.Password = Password.Text;
reportRequest.Country = Country.Text;
reportRequest.AccountNumber = AccountNumber.Text;
reportRequest.AccountType = AccountType.Text;
reportRequest.ReportType = ReportType.Text == "" ? 0 : Convert.ToInt32(ReportType.Text);
reportRequest.PhoneInfo = PhoneInfo.Text;
await GoThereAsync(reportRequest);
}
public async Task<Uri> GoThereAsync(ReportRequest reportRequest)
{
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("http://localhost:7789/");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("text/plain"));
var response = await client.PostAsJsonAsync<ReportRequest>("api/switch/reports", reportRequest);
if (response.IsSuccessStatusCode)
{
return response.RequestMessage.RequestUri;
}
return null;
}
}
To summarise: Emulator.aspx does POST to web api. Web API sets cookies and location to home.aspx. Home.aspx receives cookies (debug steps into code-behind) but browser remains on Emulat.aspx and does not render home.aspx.
Try CookieHeaderValue.Path = "/".
From the Microsoft Docs:
Path: Restricts the cookie to the specified path within the domain. If not specified, the path of the request URI is used.
Related
I am using the Authorize.net Accept Hosted "Get Hosted Profile Page" action using redirect instead of iframe. Everything is working so far, redirect is happening, token is getting passed . . . but there is literally no button to proceed and/or go back to my site after the customer is redirected to this page (?). Am I missing something? I am passing a redirect URL in to get my token, so I'd expect there to be something happening.
I'm using the .NET SDK on my backend.
string token = null;
var settings = new settingType[]
{
new settingType
{
settingName = settingNameEnum.hostedProfileReturnUrl.ToString(),
settingValue = model.ReturnUrl.AbsoluteUri
// ^^^ here's why my redirect url goes
}
};
var profileReq = new getHostedProfilePageRequest();
profileReq.customerProfileId = model.CustomerProfileId;
profileReq.hostedProfileSettings = settings;
var controller = new getHostedProfilePageController(profileReq);
controller.Execute();
var resp = controller.GetApiResponse();
// ^^^ this all works fine, token is returned
Here's the page to which I'm redirected at https://test.authorize.net/customer/manage (the sandbox), below. There's no button to advance or go backwards. I've tried clicking everywhere.
How do I get back to my site?
My website is running fine. Basically I am having some html pages that calls a webapi to get the results and bind the chart. The api only sends the json data and rest is done on html page in script tag.
Now I have to integrate some of my website pages into another website so I have created the html pages but when I run them I am getting Error - 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'null' is therefore not allowed access.
The mvc code:
[HttpGet, Route("DevD"), OutputCache(Duration = 5, VaryByHeader = "Origin")]
public ActionResult GetDevD(double value1)
{
return Json(_devD, JsonRequestBehavior.AllowGet);
}
private static object _devD;
private static object GetDevD()
{
dynamic trend = Trend;
return new
{
trend?.day,
volume = new abc(GetLastTick("JZ"))
};
}
In global.ascx
protected void Application_BeginRequest()
{
var origin = Request.Headers["Origin"];
if (!string.IsNullOrWhiteSpace(origin) && (origin.EndsWith("abc.com") || origin.EndsWith("www.watrade.net")))
{
Response.Headers.Add("Access-Control-Allow-Origin", origin);
Response.Headers.Add("Access-Control-Allow-Headers", "accept, content-type");
}
if (Request.HttpMethod != "OPTIONS") return;
Response.End();
}
I don't want to use any plugin. What changes should I made in this code so that it runs in my website also and can be integrated in another website also.
I want to authenticate a user from my wp8 app using users google login credentials. So that I can get profile info of user. I found two articles in web with source code. But I was unable to get what I want.
First code I've found in this Link. But after getting authentication code it didn't have any code to get profile. May be I could not understand.
Second code I've found in this Link. It was following mvvm pattern, so I was totally blank to understand this code.
If anyone have used it properly, please help me. What actually I want that after getting client id and client secret what to do in app to get user's profile info. Helps are appreciated. Thanks in advance.
Here is code
protected override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
IDictionary<string, string> parameters = this.NavigationContext.QueryString;
string authEndpoint = parameters["authEndpoint"];
string clientId = parameters["clientId"];
string scope = parameters["scope"];
string uri = string.Format("{0}?response_type=code&client_id={1}&redirect_uri={2}&scope={3}",
authEndpoint,
clientId,
"urn:ietf:wg:oauth:2.0:oob",
scope);
webBrowser.Navigate(new Uri(uri, UriKind.Absolute));
}
private async void LayoutRoot_Loaded(object sender, RoutedEventArgs e)
{
if(!App.loggedin)
{
OAuthAuthorization authorization = new OAuthAuthorization(
"https://accounts.google.com/o/oauth2/auth",
"https://accounts.google.com/o/oauth2/token");
TokenPair tokenPair = await authorization.Authorize(
"YOUR_CLIENT_ID",
"CLIENT_SECRET",
new string[] { GoogleScopes.UserinfoEmail });
// Request a new access token using the refresh token (when the access token was expired)
TokenPair refreshTokenPair = await authorization.RefreshAccessToken(
"YOUR_CLIENT_ID",
"CLIENT_SECRET",
tokenPair.RefreshToken);
}
}
what to do after getting access token?
This is the code that allows you to view the profile details:
private void LoadProfile(string access_token)
{
Debug.WriteLine("loading profile");
RestClient client = new RestClient("https://www.googleapis.com");
client.Authenticator = new OAuth2AuthorizationRequestHeaderAuthenticator(access_token);
var request = new RestRequest("/oauth2/v1/userinfo", Method.GET);
client.ExecuteAsync<Profile>(request, ProfileLoaded);
}
private void ProfileLoaded(IRestResponse<Profile> response)
{
Profile = response.Data;
}
Just pass in the access_token you got from your prior code and the data should be contained in response.Data
Assume we have an application that wants access popular Russian social network VK and written on C# with WinForms GUI. VK uses OAuth2-similiar approach, so we need to open web browser with vk oauth authorization url. Then we subscribe to webBrowser's OnNavigated event and waiting until url will not be equal some pre-defined url with access token in query string.
From now on we can call vk methods using received access token, but some strange things take place here: when i try to invoke some vk methods with HttpClient.GetAsync(methodUri), everything goes according to plan, except to opening the link from the authorization web browser in the system web browser.
vk's client authorization Url looks like https://oauth.vk.com/authorize?client_id={clientId}&scope={scope}&redirect_uri=https://oauth.vk.com/blank.html&display={displayType}&response_type=token, Url with received accessToken looks like https://oauth.vk.com/blank.html#access_token={accessToken}&expires_in={expiresIn}&user_id={userId}, note the number sign instead on question mark.
code in main form:
var authenticationForm = new AuthenticationForm();
authenticationForm.Show();
_authenticatedUser = await application.ClientAuthenticator.Authenticate(authenticationForm.GetToken);
authenticationForm.Close();
var httpClient = new HttpClient();
var request = "https://api.vk.com/method/users.get.xml?user_ids=1&fields=online";
var response = await httpClient.GetAsync(request);
authenticationForm class code:
public partial class AuthenticationForm : Form
{
private readonly TaskCompletionSource<VkAccessToken> _tokenCompletitionSource = new TaskCompletionSource<VkAccessToken>();
private Uri _redirectUri;
public AuthenticationForm()
{
InitializeComponent();
}
public async Task<IVkAccessToken> GetToken(Uri authUri, Uri redirectUri)
{
authenticationBrowser.Navigate(authUri);
_redirectUri = redirectUri;
var token = await _tokenCompletitionSource.Task;
return token;
}
private async void authenticationBrowser_Navigated(object sender, WebBrowserNavigatedEventArgs e)
{
if (!(_redirectUri.IsBaseOf(e.Url) && _redirectUri.AbsolutePath.Equals(e.Url.AbsolutePath))) return;
//working with e.Url to achieve token, userId and expiresIn, creating token variable based on them
_tokenCompletitionSource.SetResult(token);
}
}
ClientAuthenticator.Authenticate code:
public async Task<IVkAuthenticatedUser> Authenticate(Func<Uri, Uri, Task<IVkAuthenticatedUser>> aunthenticationResultGetter)
{
var authorizationUri =
new Uri("https://oauth.vk.com/authorize?client_id={clientId}&scope={scope}&redirect_uri=https://oauth.vk.com/blank.html&display=page&response_type=token");
var token = await aunthenticationResultGetter(authorizationUri, _application.Settings.RedirectUri);
//...
return newUserBasedOnToken;
}
after stepping out(using debugger) var response = await httpClient.GetAsync(request); line from main form, my system browser opens link like https://oauth.vk.com/blank.html#access_token={accessToken}&expires_in={expiresIn}&user_id={userId} - #access_token={accessToken}&expires_in={expiresIn}&user_id={userId} with recent accessToken, expiresIn and userId values. Yes, with ... - #access_token=.... in url.
I have no idea why this might happen, but I am concerned that the number sign.
important addition: it only happens if the Web browser does not have information about a session or it is expired, that is, I have to enter username and password to vk's login form. if cookies contain the necessary information and it automatically redirect to the page containing token in it's url (with # sign again), everything works as expected
I'm integrating a single sign on over 2 ASP.Net applications. For that matter i have a web service that is called by the main app. when a user logs in. this web service authenticates the user in my second application and brings back the authentication cookies i need to deliver to the client browser so he can navigate freely and logged in both applications.
I was planning to use HttpContext.Current.Response.Cookies.Add(cookie) in order to deliver the new cookies but this seems not to work as no cookies are added what so ever...
Any ideas on what might be going wrong?
here is my code:
var service = new localhost.UserManagement();
service.CookieContainer = new CookieContainer();
if (service.AuthenticateUser("test#user.pt", "test"))
{
var collection = service.CookieContainer.GetCookies(new Uri("http://localhost"));
foreach (Cookie item in collection)
{
HttpContext.Current.Response.Cookies.Add(CookieConverter(item));
}
HttpContext.Current.Response.Flush();
return true;
}
return false;
Note: CookieConverter(item) is used to convert Cookie object i receive to HttpCookie
Thanks
private HttpCookie CookieConverter(Cookie cookie)
{
var result = new HttpCookie(cookie.Name);
result.Value = cookie.Value;
result.Domain = cookie.Domain;
result.Expires = cookie.Expires;
result.Path = cookie.Path;
result.Secure = cookie.Secure;
result.HttpOnly = cookie.HttpOnly;
return result;
}
You should check:
collection is empty? Could you set braeakpoint and check collection?
where is this code located? (.aspx page, web service, http handler?)
try to create minimalistic "Cookie setter" that just add simple cookie in any way