how to call webservices using ajax in asp.net mvc 5 - javascript

I am working on a asp.net mvc 5 and I want to use web api in it and I use a jquery library and below code.but I didnot get proper answer .it returns always fail but I can see the output in the browser.please help me
<!DOCTYPE html>
<html>
<head>
<title></title>
<meta charset="utf-8" />
<script src="js/jquery-1.12.4.js"></script>
<script>
function ftoken() {
$.ajax({
url: 'http://charter724.ir/webservice/get_city_a.php?id=367&key=EmlyCD8JOWX22cL8IuNBju5K5',
// data: { },
type: 'GET',
dataType: 'json',
success: function (data) {
alert('success')
// alert(data.data)
//if (country_id != "" && zone_code != "" && duration != "" && birthday != "") {
// fPrice(data.token);
//}
//$.each(data, function (idx, result) {
// alert(result.data);
//})
},
error: function (x, y, z) {
alert('fail')
//alert(x.responseText);
//alert(z);
}
});
}
</script>
</head>
<body>
<input type="submit" name="name" onclick="ftoken();" value="Click " />
</body>
</html>
I can see the output in the browser

You will not be able to make an AJAX call to this URL because of the Same Origin Policy(Yes you can copy and paste the URL in the browser and get a response, but you cannot access it from javascript).
Same origin policy states that AJAX calls will only be allowed if they are coming from the same domain, you are doing something like this:
making an AJAX call from http://localhost... to http://charter724... - this is not allowed
If you inspect the browser console you will see an error similar to the one below:
XMLHttpRequest cannot load http://charter724.ir/webservice/get_city_a.php?id=367&key=EmlyCD8JOWX22cL8IuNBju5K5. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:10585' is therefore not allowed access
The only way around this is for you to contact the company exposing the charter724 service and ask them to enable CORS(Cross Origin Resource Sharing) and allow all requests coming from your domain to access their service calls.
Alternatively you can access the service call using HttpClient and get the JSON response.If you really wanted to you could even expose your own set of services which talk to the external service and access your service calls from java script:
public async System.Threading.Tasks.Task<ActionResult> Index()
{
string url = "http://charter724.ir/webservice/get_city_a.php?id=367&key=EmlyCD8JOWX22cL8IuNBju5K5";
System.Net.Http.HttpClient client = new System.Net.Http.HttpClient();
System.Net.Http.HttpResponseMessage response = await client.GetAsync(url);
response.EnsureSuccessStatusCode();
string responseBody = await response.Content.ReadAsStringAsync();
return View();
}

Related

How to pass an Access Token from .NET (code behind) to Javascript

I would like to "authorize" via the .NET framework using my own API keys, secret and Refresh Token, and then pass the Access Token to JavaScript so I can upload a video directly to YouTube with a progress indicator.
I have working code via the .NET API that will accomplish the upload directly to my channel [without authorization], but you get no progress indication (and it can take quite some time) and the file must be uploaded to my server first, then to YouTube server.
Is a server side access code different from a client side access code? If not:
How can I obtain the access code server side? (get the string)
***How can I pass it to Google APIs via JavaScript? (not how to write <%= access code %> but where to pass it in?)
I am well aware of the security risk in exposing the access token, but these do expire right? (as a bonus, how can I shorten the expire time). This is also being done inside a password protected web page, and you don't get the 'client secret' or 'refresh token'
***update - I think I found where to pass in the token, in the MediaUploader object.
var uploader = new MediaUploader({
baseUrl: 'https://www.googleapis.com/upload/youtube/v3/videos',
file: selectedFile,
token: token, // ***RIGHT HERE***
metadata: metadata,
params: params,
onError: function(data) {
Okay, so after weeks of smashing my way through the APIs, .NET, and JavaScript documentation I have built the following solution....
As per the YouTube V3 Developer documentation get your Keys all set up. (choose OAuth, Web Application, and enter URIs for both your Javascript and Redirect code)
Next use the OAuth Playground to obtain your Refresh Code
Once you have your client_id, client_secret, and refresh_token you are ready to rock!
This code makes a simple HTTP/REST call via the code behind to obtain an access_token which is good for 3600 seconds (the default). It then passes this string to the JavaScript code for use ****WARNING****
This does not use any of the .NET or JavaScript Libraries with the exception of one file, the cors_upload.js available on GitHub
Allas, the code
Default.aspx
<%# Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="ApisCallTest.WebForm1" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<meta charset="utf-8" />
<title>YouTube API Uploads via CORS</title>
<style>
#disclaimer {
font-size: 0.75em;
color: #aeaeae;
max-width: 350px;
}
.during-upload { display: none; }
label { display: block; }
input[type="text"],
textarea,
progress {
font-size: 16px;
width: 15em;
margin-bottom: 1em;
padding: 0.5em;
font-family: "Open Sans", sans-serif;
}
</style>
</head>
<body>
<div>
<input input type="file" id="file" class="button" accept="video/*" />
<button id="button">Upload Video</button>
</div>
<div class="during-upload">
<p><span id="percent-transferred"></span>% done (<span id="bytes-transferred"></span>/<span id="total-bytes"></span> bytes)</p>
<progress id="upload-progress" max="1" value="0"></progress>
</div>
<p id="disclaimer">By uploading a video, you certify that you own all rights to the content or that you are authorized by the owner to make the content publicly available on YouTube, and that it otherwise complies with the YouTube Terms of Service located at http://www.youtube.com/t/terms</p>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script src="cors_upload.js"></script>
<script>
$('#button').on("click", goForUpload);
function goForUpload() {
if ($('#file').get(0).files[0]) {
$('#button').attr('disabled', true);
var uploadStartTime = 0;
var metadata = {
snippet: {
title: 'PUT YOU TITLE HERE',
description: 'THIS IS YOUR VIDEO DESCRIPTION',
categoryId: '22'
},
status: {
privacyStatus: 'unlisted'
}
};
var uploader = new MediaUploader({
baseUrl: 'https://www.googleapis.com/upload/youtube/v3/videos',
file: $('#file').get(0).files[0],
token: '<%= access_token %>',
metadata: metadata,
params: {
part: Object.keys(metadata).join(',')
},
onError: function (data) {
var message = data;
// Assuming the error is raised by the YouTube API, data will be
// a JSON string with error.message set. That may not be the
// only time onError will be raised, though.
try {
var errorResponse = JSON.parse(data);
message = errorResponse.error.message;
} finally {
alert(message);
}
},
onProgress: function (data) {
var currentTime = Date.now();
var bytesUploaded = data.loaded;
var totalBytes = data.total;
// The times are in millis, so we need to divide by 1000 to get seconds.
var bytesPerSecond = bytesUploaded / ((currentTime - this.uploadStartTime) / 1000);
var estimatedSecondsRemaining = (totalBytes - bytesUploaded) / bytesPerSecond;
var percentageComplete = (bytesUploaded * 100) / totalBytes;
$('#upload-progress').attr({
value: bytesUploaded,
max: totalBytes
});
$('#percent-transferred').text(percentageComplete);
$('#bytes-transferred').text(bytesUploaded);
$('#total-bytes').text(totalBytes);
$('.during-upload').show();
},
onComplete: function (data) {
var uploadResponse = JSON.parse(data);
alert('all done, you can store this id: ' + uploadResponse.id)
}
});
uploadStartTime = Date.now();
uploader.upload();
}
}
</script>
</body>
</html>
and Default.aspx.cs
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Threading.Tasks;
using Newtonsoft.Json.Linq;
namespace ApisCallTest
{
public partial class WebForm1 : System.Web.UI.Page
{
private static readonly HttpClient client = new HttpClient();
public string access_token;
protected void Page_Load(object sender, EventArgs e)
{
var values = new Dictionary<string, string>
{
{ "client_id", "REPLACE_ME" },
{ "client_secret", "REPLACE_ME" },
{ "refresh_token", "REPLACE_ME" },
{ "grant_type", "refresh_token" }
};
var content = new FormUrlEncodedContent(values);
var response = client.PostAsync("https://www.googleapis.com/oauth2/v4/token", content);
string json = response.Result.Content.ReadAsStringAsync().Result;
dynamic obj = JObject.Parse(json);
access_token = obj.access_token;
}
}
}
The result... From a password protected web page I can have a user upload a video to MY channel, unlisted, and store the video ID to later embed that video back on my website.
as for the ****WARNING****, this is somewhat of a security concern as you are exposing (very directly) your PERSONAL access key to the "public". It only lasts for 1 hour, but gives whatever "scope" of access you are using to "anyone" It would be a good idea to try and obstuficate the key somewhat, and at the very least, don't do this on a publicly available page.

symfony 3 ajax redirect if session is expired

In my Symfony 3 app I made so, that if the user is inactive for some time, it is logged out and requested to login again. This is done with the following code:
//RequestListener.php
public function onKernelRequest(GetResponseEvent $event)
{
if (HttpKernelInterface::MASTER_REQUEST != $event->getRequestType()) {
return;
}
if ($this->maxIdleTime > 0) {
$lapse = time() - $this->session->getMetadataBag()->getCreated();
$lapse_short = time() - $this->session->getMetadataBag()->getLastUsed();
if ($lapse >= $this->maxIdleTime || $lapse_short >= $this->shortIdleTime) {
$username = $this->securityToken->getToken()->getUser();
if ($username !== 'anon.'){
$this->session->invalidate();
$this->securityToken->setToken(null);
$event->setResponse(new RedirectResponse($this->router->generate('login')));
}
}
}
}
But in ths case redirect to login form is happened when the page is reloaded. I also want to force redirect on every ajax call also. By default my ajax calls are served by the following address: /ajax
But when the session is expired the ajax is 'redirected' to my login page address and in browsers Network tab I see the following:
My ajax function which is supposed to redirect is as follows:
function requestAjax(json_data, url) {
if(url.indexOf('login') !== -1){
window.location = './login';
}
var request = $.ajax({
url: root + '/' + url
, method: 'post'
, data: json_data
});
return request;
}
But no redirect is happened. So The question is how to force redirect on expired sessions and ajax calls and also why ajax status is 200 but not say 302 in this case? Thank you
UPD_1 My services.yml for RequestListener.php
app.handler.session_idle:
class: AppBundle\EventListener\RequestListener
arguments: ["#session", "#security.token_storage", "#router", "#app.logger", "%session_lifetime%", "%session_active_lifetime%", "%instance_path%"]
tags:
- { name: kernel.event_listener, event: kernel.request, method: onKernelRequest }
You could try something like this (tested and working in Symfony 2.8)
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
class AjaxAuthenticationListener {
/*
* function onCoreException
* Check if session is expired and handles security related exceptions
* #param GetResponseForExceptionEvent $event An GetResponseForExceptionEvent instance
*
*/
public function onCoreException(GetResponseForExceptionEvent $event) {
$exception = $event->getException();
$event_request = $event->getRequest();
$session = $event->getRequest()->getSession();
if ($event_request->isXmlHttpRequest()) {
if ($exception instanceof AuthenticationException || $exception instanceof AccessDeniedException) {
$session->getFlashBag()->add('warning', 'You have been signed out automatically due to inactivity.');
$event->setResponse(new Response('Session expired', 403));
}
}
}
}
As you can see, "onCoreException" function returns a 403 status code.
Now, in home page (in my case) or page where you will have ajax calls, you could use "ajaxError" and catch the jqXHR.status, if it is 403, then redirect to login page and using a "FlashBag" to display a message related to expired session.
$(document).ready(function () {
//Catch AjaxAuthenticationListener response
$(document).ajaxError(function (event, jqXHR) {
if (403 === jqXHR.status) {
$(location).attr('href', '{{ path('login') }}');
}
});
I have omitted explain how "onCoreException" function works as a service and how it handles the session when it has been expired, taking into account that this part is working properly in your code.
services.yml:
app.gt.ajax.authentication.listener:
class: AppBundle\EventListener\AjaxAuthenticationListener
tags:
- { name: kernel.event_listener, event: kernel.exception, method: onCoreException, priority: 1000 }
I hope this is useful for you.
Symfony 5 solution
Have been researching on this care for quite some hours. In the symfony 5 How to Customize Access Denied Responses docs, you can customize one of the following:
1. App entry point
2. Access denied handler
3. All Access Denied Responses
Going with customizing All Access Denied Responses, i created a kernel.exception subscriber/listener:
namespace App\EventSubscribers;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Event\ExceptionEvent;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
class AccessDeniedHandler implements EventSubscriberInterface
{
public static function getSubscribedEvents(): array
{
return [
// the priority must be greater than the Security HTTP
// ExceptionListener, to make sure it's called before
// the default exception listener
KernelEvents::EXCEPTION => ['onKernelException', 2]
];
}
public function onKernelException(ExceptionEvent $event): void
{
// Ajax is returning login page instead of session expired/access denied
// Creating a custom handler for ajax
// more at https://symfony.com/doc/current/security/access_denied_handler.html#customize-the-unauthorized-response
$request = $event->getRequest();
if($request->isXmlHttpRequest()){
$event->setResponse(new Response('Your session has expired!', 403));
return;
}
}
}

Trying to send value from javascript to python server

I have multiple input tags, my task is to collect the values entered by the user and send it back to the server. I am using Django as my framework. I am successful in sending the data to the client side (javascript).
To return back the data from javascript function to my python function, I used XMLHttpRequest.
I have added my code below:
<html>
<head>
<style>label{ text-align:center; width:250px; color:blue; display:inline-block}</style>
<script type="text/javascript" src="'+url_read+'"></script>
<script>
function submit_this()
{
var i,j;var arr=[];
for(i=0; i<Hello.length; i++)
{
arr[i]=[];
for(j=0;j<Hello[i].length; j++)
{
arr[i].push(document.getElementById(Hello[i][j]).value);
}
}
alert(document.getElementById(Hello[1][0]).value);
xmlHttpReq = new XMLHttpRequest();
xmlHttpReq.open('POST', '/button_click',true);
xmlHttpReq.send('w=' + encodeURI(arr));
}
</script>
</head>
<body>
<center>
<button id="submit_button" onclick="submit_this();" value="Submit">Submit</button>
</center>
</body>
</html>
The above code is stored in a string called html_string.
Hello is a json object read from the file denoted by the varible url_read. It was dumped using Python.
The plan was to use HttpResponse to send the html_string and render the html page in return.
I understand that I need to make one POST function in one of the classes in views.py. But unable to understand how to approach this problem.
I have to somehow send the javascript data structure named arr back to the server side. The main doubt is where can I put my code where I can read the value posted by the javascript function.
I want to navigate to a new page once submit button has been pressed and in Django each url has a new function (in views.py) associated with it. Should I place it in that ?
Here is an example where in I am sending values to (Django)python server using JS, and receiving html rendered template.
I am using ul tag with id #Nearby to load html inside an html.
Ajax success is returning html from django view rendered through url endpoint '/getGopoints/'
template.html
<div class="row">
<div>
<ul id="Nearby">
</ul>
</div>
</div>
<script>
$(document).ready(function(){
$('#dataTables-example1').DataTable({
responsive: true
});
getLocation();
});
function getLocation() {
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(showPosition);
}
}
function showPosition(position) {
$.ajax({
url : '/getGopoints/', // the endpoint
type : 'GET', // http method
data : { 'lat' : position.coords.latitude,
'lon' : position.coords.longitude,
'csrfmiddlewaretoken': '{{csrf_token}}'
}, // data sent with the post request
// handle a successful response
success : function(data) {
$('#Nearby').html(data);
},
dataType: 'html'
});
}
</script>
urls.py
url(r'^getGopoints/$',views.getGopoints, name='getGopoints'),
views.py
def getGopoints(request):
lat = str(request.GET['lat'])
lon = str(request.GET['lon'])
pnt=fromstr('POINT(%s %s)' %(lon,lat))
with_in_distance = 20
go_points = GoPoint.objects.filter(point__distance_lte=(pnt, D(km=with_in_distance)))
context = RequestContext(request,
{'go_points':go_points,
'with_in_distance':with_in_distance,
})
return render_to_response('nearby.html',
context_instance=context)

How to secure Vert.x 3.3 Eventbus Bridge with Keycloak

I'm currently writing a simple prototype Vert.x 3.3 application (Latest Github build using Jitpack.io) that tries to secure http endpoints and the eventbus with Keycloak.
I have two verticals and static index page with a button to send messages. Everything works fine unsecured but I don't know how to secure the SockJS eventbus bridge with Keycloak. Securing the http endpoint works fine.
Since Vert.x 3.3 is not officially released yet I haven't been able to find very much information.
http://vertx.io/blog/vertx-3-and-keycloak-tutorial/ only covered securing the http endpoint and the 3.21 documentation on requiring authorization is specifically for using the BasicAuthHandler which I'm not sure how to modify to work with Keycloak:
http://vertx.io/docs/vertx-web/java/#_requiring_authorisation_for_messages
Currently I have the following code:
public class VertxEventBusTest extends AbstractVerticle {
#Override
public void start(Future<Void> startFuture) throws Exception {
System.out.println("Primary Verticle Started");
Router router = Router.router(vertx);
HttpServer server = vertx.createHttpServer().requestHandler(router::accept);
OAuth2Auth oAuth2Auth = OAuth2Auth.createKeycloak(vertx, OAuth2FlowType.AUTH_CODE, getKeycloakJson());
OAuth2AuthHandler oAuth2AuthHandler = OAuth2AuthHandler.create(oAuth2Auth, "http://localhost:8091");
oAuth2AuthHandler.setupCallback(router.get("/callback"));
SockJSHandlerOptions options = new SockJSHandlerOptions().setHeartbeatInterval(2000);
BridgeOptions bridgeOptions = new BridgeOptions();
bridgeOptions.addInboundPermitted(new PermittedOptions().setAddress("click"));
bridgeOptions.addOutboundPermitted(new PermittedOptions().setAddress("click"));
SockJSHandler sockJSHandler = SockJSHandler.create(vertx, options).bridge(bridgeOptions);
router.route("/").handler(oAuth2AuthHandler);
router.route("/eventbus/*").handler(oAuth2AuthHandler);
router.route("/eventbus/*").handler(sockJSHandler);
vertx.eventBus().<JsonObject>consumer("click", msg -> System.out.println("Msg Received on Verticle1: " + msg.body()));
router.route().handler(StaticHandler.create().setWebRoot("webroot"));
server.listen(8091, result -> {
if (result.succeeded()) {
startFuture.complete();
} else {
startFuture.fail(result.cause());
}
});
}
private JsonObject getKeycloakJson() {
return new JsonObject("{\n" +
" \"realm\": \"Prototype\",\n" +
" \"realm-public-key\": \"<public key>",\n" +
" \"auth-server-url\": \"http://localhost:8180/auth\",\n" +
" \"ssl-required\": \"external\",\n" +
" \"resource\": \"prototype-eventbus\",\n" +
" \"credentials\": {\n" +
" \"secret\": \"<secret>\"\n" +
" }\n" +
"}");
}
}
My Static Html is:
<head>
<meta charset="UTF-8">
<script src='sockjs-0.3.4.js'></script>
<script src='vertx-eventbus.js'></script>
<script src='index-js.js'></script>
<title>VERT.X Test</title>
</head>
<body onload="load()">
<!-- JavaScript includes. -->
<button onclick="zclicker()">Test Click</button>
</body>
</html>
Javascript:
var eb = new EventBus('http://localhost:8091/eventbus');
function load() {
eb.onopen = function () {
eb.registerHandler('click', function (data) {})
};
}
function zclicker() {
eb.publish('click', {
'clicked': true
});
}
When running the vertical there are no errors but chrome developer tools shows the following error after login through keycloak:
XMLHttpRequest cannot load http://localhost:8180/auth/realms/Prototype/protocol/openid-connect/auth?re…direct_uri%3D%2Feventbus%2Finfo&state=&client_id=prototype-eventbus&scope=. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8091' is therefore not allowed access.
That looks like a CORS issue.
By the looks of your error you might just be able to add the following header in the response:
Access-Control-Allow-Origin: *
or
Access-Control-Allow-Origin: http://localhost:8091
depending on how much you care about security.
That's usually sufficient for simple GET for text/html, but if you want to handle other content types (eg JSON) or PUT / or DELETE methods, then you'll have to add more headers to allow them.
Some resources:
http://enable-cors.org/server.html
http://www.html5rocks.com/en/tutorials/cors/

Trigger cross domain YQL ajax request with input onBlur

I have a form to collect information about a product (i.e. from Amazon). I am attempting to trigger a YQL ajax request on blur of the URL input. Currently, no errors in console, but no results either. Here is my form input:
<div class="uk-form-row">
<div class="uk-form-label"><?php echo $this->form->getLabel('item_url'); ?></div>
<div class="uk-form-controls "><input type="text" name="jform[item_url]" id="jform[item_url]" value="<?php if (!empty($this->item->id)) { echo $this->item->item_url;}; ?>" class="uk-form-large uk-width-medium-1-1" placeholder="http://" aria-required="required" required="required"/></div>
</div>
<script type="text/javascript">
jQuery( "#jform[item_url]" ).blur(function() {
var path = jQuery('#jform[item_url]').val();
requestCrossDomain(path, function(results) {
jQuery('#url_results').html(results);
});
});
</script>
<div id="url_results">
</div>
My function:
// Accepts a url and a callback function to run.
function requestCrossDomain( site, callback ) {
// If no url was passed, exit.
if ( !site ) {
alert('No site was passed.');
return false;
}
// Take the provided url, and add it to a YQL query. Make sure you encode it!
var yql = 'http://query.yahooapis.com/v1/public/yql?q=' + encodeURIComponent('select * from html where url="' + site + '"') + '&format=xml&callback=cbFunc';
// Request that YSQL string, and run a callback function.
// Pass a defined function to prevent cache-busting.
jQuery.getJSON( yql, cbFunc );
function cbFunc(data) {
// If we have something to work with...
if ( data.results[0] ) {
// Strip out all script tags, for security reasons.
// BE VERY CAREFUL. This helps, but we should do more.
data = data.results[0].replace(/<script[^>]*>[\s\S]*?<\/script>/gi, '');
// If the user passed a callback, and it
// is a function, call it, and send through the data var.
if ( typeof callback === 'function') {
callback(data);
}
}
// Else, Maybe we requested a site that doesn't exist, and nothing returned.
else throw new Error('Nothing returned from getJSON.');
}
}
Here's the fiddle: http://jsfiddle.net/FLY66/2/
This issue is more related to your server. You can simply set the Access-Control-Allow-Origin header on your server. Look for your server language to see how to set Access-Control-Allow-Origin
Setting it to * will accept cross-domain AJAX requests from any domain.
Another alternative is use 'JSONP' data type for returned data.
References
http://en.wikipedia.org/wiki/Same_origin_policy
https://developer.mozilla.org/en/http_access_control

Categories

Resources