Disable Csrf for ajax query - javascript

I'm using Laravel 5.1 and i'm tryin to disable csrf validation for this route to be able to perform some remote validations using Jquery Form Validator :
Route::post('verify', 'formController#check');
As mentioned in the documentation, I just have to add my URI to the $excludeproperty. whice I did :
namespace App\Http\Middleware;
use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as BaseVerifier;
class VerifyCsrfToken extends BaseVerifier
{
/**
* The URIs that should be excluded from CSRF verification.
*
* #var array
*/
protected $except = [
'verify',
];
}
That did not work, So I tried to disable csrf validation for the whole application :
class Kernel extends HttpKernel
{
protected $middleware = [
...
//\App\Http\Middleware\VerifyCsrfToken::class,
];
protected $routeMiddleware = [
...
];
}
That did not work either. I keep getting this error on the console :
POST http://domain.name/verify 500 (Internal Server Error)
whice exactly points to this line(The validator's js file):
ajax({url:b,type:"POST",cache:!1,data:g,dataType:"json",error:function(a){return h({valid:!1,message:"Connection failed with status: "+a.statusText},f),!1}
What am I missing? thanks for your help.

namespace App\Http\Middleware;
use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as BaseVerifier;
class VerifyCsrfToken extends BaseVerifier
{
protected $except_urls = [
'verify'
];
public function handle($request, Closure $next)
{
$regex = '#' . implode('|', $this->except_urls) . '#';
if ($this->isReading($request) || $this->tokensMatch($request) || preg_match($regex, $request->path()))
{
return $this->addCookieToResponse($request, $next($request));
}
throw new TokenMismatchException;
}
}

Solved the problem.
For Laravel 5 and above, adding protected $except = ['verify',]; to App\Http\Middleware\VerifyCsrfToken.php does solve the problem.
NB : Google's inspect tool (Network menu) helped me understand what was really happening.

Related

React Native: How can I send events from iOS (Swift) back to JavaScript?

I am working on a project where I want to integrate React-Native into a native Swift app. To make sure both sides are aware of state, I've made a 'message bus', A mechanism through which events can be passed from Javascript to native, and vice versa.
This works like a charm when sending an event from JS to iOS; it gets received, parsed and my Swift code knows exactly what to do. Sending an event from Swift to Javascript seems a lot harder - and poorly documented - as I find myself stuck on an error:
terminating with uncaught exception of type NSException
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Error when sending event: RCTCrossPlatformEventBus.Event with body: { "name" : "Authenticated", "data" : "{\"firstName\":\"1\",\"email\":\"34\",\"lastName\":\"2\",\"password\":\"3\"}" }. RCTCallableJSModules is not set. This is probably because you've explicitly synthesized the RCTCallableJSModules in RCTEventEmitter, even though it's inherited from RCTEventEmitter.'
This error seems to be common as there are a lot of stack overflow questions and GitHub issues to be found on it. However, nearly all of them date back from ±5 years ago, and simply don't help me with my issue any more. Below, I'm listing my implementation. If anybody could provide me with some guidance on how to solve this issue, it would be highly appreciated.
RCTCrossPlatformEventBus.m
#import <Foundation/Foundation.h>
#import "React/RCTBridgeModule.h"
#import "React/RCTEventEmitter.h"
#interface RCT_EXTERN_MODULE(RCTCrossPlatformEventBus, RCTEventEmitter)
RCT_EXTERN_METHOD(supportedEvents)
RCT_EXTERN_METHOD(processHybridEvent: (NSString *)name) // this receives JS events
#end
RCTCrossPlatformEventBus.swift
#objc(RCTCrossPlatformEventBus)
open class RCTCrossPlatformEventBus: RCTEventEmitter {
override init() {
super.init()
}
static let appShared = RCTCrossPlatformEventBus()
#objc
public override static func requiresMainQueueSetup() -> Bool {
return true
}
/// Processes a received event received from hybrid code
/// - Parameters:
/// - json: the json encoded string that was sent
#objc func processHybridEvent(_ json: String) {
print("Swift Native processing event: \(json)")
DispatchQueue.main.async {
var jsonObject: [String: Any]?
if let jsonData = json.data(using: .utf8), let dict = try? JSONSerialization.jsonObject(with: jsonData, options: .mutableContainers) as? [String:Any] {
jsonObject = dict
}
NotificationCenter.default.post(name: .RCTCrossPlatformEventBusEvent, object: self, userInfo: jsonObject)
}
}
/// Posts an event to both the hybrid code
/// - Parameters:
/// - json: the json encoded string that will be sent
#objc func postEvent(json: String) {
self.sendEvent(withName: "RCTCrossPlatformEventBus.Event", body: json)
}
open override func supportedEvents() -> [String]! {
return ["RCTCrossPlatformEventBus.Event"]
}
open override func constantsToExport() -> [AnyHashable : Any]! {
return [:]
}
}
App_Bridging_Header.h
#ifndef ArchitectureDemo_Bridging_Header_h
#define ArchitectureDemo_Bridging_Header_h
#import "React/RCTBridgeModule.h"
#import "React/RCTEventEmitter.h"
#import "RCTCrossPlatformEventBus.m"
Then, in Javascript (Typescript actually)
import { NativeModules, NativeEventEmitter } from 'react-native'
import { BehaviorSubject, Observable } from 'rxjs'
const { CrossPlatformEventBus } = NativeModules;
const eventEmitter = new NativeEventEmitter(CrossPlatformEventBus)
class RNCrossPlatformEventBus {
// we set up a private pipeline for events we can post to
private postableEventBus = new BehaviorSubject<string>('')
// and then expose it's observable for everyone to subscribe to
eventBus = this.postableEventBus.asObservable()
constructor() {
eventEmitter.addListener('RCTCrossPlatformEventBus.Event', (body) => {
this.processEventFromNative(body)
})
}
postEvent(json: string) {
this.postableEventBus.next(json)
CrossPlatformEventBus.processHybridEvent(json);
}
processEventFromNative(jsonString: string) {
this.postableEventBus.next(jsonString)
console.log(`React-Native received event from native ${jsonString}`)
}
}
export default new RNCrossPlatformEventBus()
I resolved my problem in the meantime and am posting the answer here for future reference.
As it turns out, initializing my RCTCrossPlatformEventBus - as I do in my swift file - Is an invalid operation. React-Native already initialize this, so rather than creating a singleton myself, I just had to override it's initializer like so:
open class RCTCrossPlatformEventBus: RCTEventEmitter {
public static var shared: RCTCrossPlatformEventBus?
override init() {
super.init()
RCTCrossPlatformEventBus.shared = self
}
...

X-Total-Count missing header error in React Admin with Spring Boot API

I have my Spring Boot REST API. Link: "http://localhost:8080/api/components/component/list"
For the frontend, I am using React, above is the link that I want the "React Admin" app to consume.
Here is my Spring Boot's CORS Code, it is in a separate class called CorsConfig:
#Configuration
public class CorsConfig implements WebMvcConfigurer {
#Override
public void addCorsMappings(CorsRegistry myCorsRegistry){
myCorsRegistry.addMapping("/**")
.allowedOrigins("http://localhost:3000") //frontend's link
.allowedHeaders("Access-Control-Allow-Origin","Access-Control-Allow-Header", "Access-Control-Expose-Headers", "Content-Range", "Content-Length", "Connection", "Content-Type", "X-Total-Count", "X-Content-Type-Options", "Set-Cookies", "*")
.allowedMethods("GET", "POST", "PUT", "HEAD", "OPTIONS", "PATCH")
.allowCredentials(true)
}
}
For my controller class I have the following:
#CrossOrigin("http://localhost:3000")
#RequestMapping("/api/components/component")
#RestController
public class Component{
#Autowired
//code...
}
Here is my React Code:
import React from 'react';
import { Admin,ListGuesser, Resource} from 'react-admin';
import jsonServerProvider from "ra-data-json-server";
const parentURL =
jsonServerProvider(`http://localhost:8080/api/components/component`);
function App() {
return(
<Admin dataProvider={parentURL}>
<Resource name="list" list={ListGuesser} />
</Admin>
);
}
Here is the error I am getting in my Chrome console:
The X-Total-Count header is missing in the HTTP Response. The jsonServer Data Provider expects
responses for lists of resources to contain this header with the total number of results to build the
pagination. If you are using CORS, did you declare X-Total-Count in the Access-Control-Expose-Headers
header?
In my JavaScript code:
When I use restProvider, I get the "Content-Range header is missing in the HTTP Response" error
When I use jsonServerProvider, I get the "X-Total-Count header is missing in the HTTP Response" error
My Question:
How to fix the above error?
In the RestController add crossorigin base on your client
#CrossOrigin(origins = {"http://localhost:3000"}, exposedHeaders = "X-Total-Count")
Create a new class ConrolAdvice to send response
#ControllerAdvice
public class ResourceSizeAdvice implements ResponseBodyAdvice<Collection<?>> {
#Override
public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
//Checks if this advice is applicable.
//In this case it applies to any endpoint which returns a collection.
return Collection.class.isAssignableFrom(returnType.getParameterType());
}
#Override
public Collection<?> beforeBodyWrite(Collection<?> body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
response.getHeaders().add("X-Total-Count", String.valueOf(body.size()));
return body;
}
}
Looks like the header to be used now is:
e.g. Content-Range: posts 0-24/319
I'm reading the Table name from the entity to expose this:
String tableName = page.getContent().get(0).getClass().getAnnotationsByType(Table.class)[0].name();
long minElement = page.getNumber() * page.getSize();
long maxElement = Math.min(minElement + page.getSize() - 1, page.getTotalElements() - 1);
long totalElements = page.getTotalElements();
String contentRange = String.format("%s %d-%d/%d", tableName, minElement, maxElement, totalElements);
response.getHeaders().add("Content-Range", contentRange);
On top of the Annotation for CORS mentioned above:
#CrossOrigin(origins = {"http://localhost:3000"}, exposedHeaders = "Content-Range")

403 (Forbidden) response from SignalR Hub using ASP.NET hosting on IIS server

I'm hosting a SignalR Hub on Windows Server 2012 with IIS as an ASP.NET Web application that I've tested successfully on my local machine. But when I publish and try to connect from a Angular application the server responds with 403 Forbidden on the /negotiate request. The Angular application is located on a different domain then the Hub server.
I've read that this is caused by a CORS issue, but I've tried every solution I can find without any change. Can it be a IIS server issue or have I missed something in my code?
The route being called is https://example.com/signalr/negotiate
SignalR Server:
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.Map("/signalr", map =>
{
map.UseCors(CorsOptions.AllowAll);
var hubConfiguration = new HubConfiguration
{
EnableJSONP = true,
EnableDetailedErrors = true
};
map.RunSignalR(hubConfiguration);
});
}
}
// Hub that handles Online user list
public class OnlineHub : Hub
{
private static List<AppUserDto> _usersOnline = new List<AppUserDto>();
public OnlineHub()
{
// Automapper Setup
MappingConfig.Init();
}
public override Task OnConnected()
{
var user = GetUser();
_usersOnline.Add(user);
Clients.All.listUpdated(_usersOnline);
return base.OnConnected();
}
public override Task OnReconnected()
{
var user = GetUser();
// Add user to list of online users if it doesn't exist
if (!_usersOnline.Any(u => u.Email == user.Email))
{
_usersOnline.Add(user);
Clients.All.listUpdated(_usersOnline);
}
return base.OnReconnected();
}
public override Task OnDisconnected(bool stopCalled)
{
var user = GetUser();
if (!_usersOnline.Any(u => u.Email == user.Email))
{
// Remove user from list of online users
_usersOnline.Remove(user);
Clients.All.listUpdated(_usersOnline);
}
return base.OnDisconnected(stopCalled);
}
private AppUserDto GetUser()
{
using (var db = new EntityDbContext())
{
// Get connected AppUserDto
var user = db.AppUsers.FirstOrDefault(u => u.UserName == Context.User.Identity.Name);
// Add user to list of online users
if (user != null)
{
return Mapper.Map<AppUserDto>(user);
}
return null;
}
}
}
Angular Application SignalR Service
import { AppSettings } from './../app.settings';
import { EventEmitter, Injectable } from '#angular/core';
declare const $: any;
#Injectable()
export class SignalRService {
// Declare the variables
private proxy: any;
private connection: any;
private authData: any;
// create the Event Emitter
public messageReceived: EventEmitter<any>;
public connectionEstablished: EventEmitter<Boolean>;
public connectionExists: Boolean;
constructor(private appSettings: AppSettings) {
// Setup
this.connectionEstablished = new EventEmitter<Boolean>();
this.messageReceived = new EventEmitter<any>();
this.connectionExists = false;
}
public initialize(proxyName: string): void {
this.connection = $.hubConnection(this.appSettings.SIGNALR_BASE_URL);
this.proxy = this.connection.createHubProxy(proxyName);
this.registerOnServerEvents();
this.startConnection();
}
private startConnection(): void {
this.connection.start({withCredentials: false})
.done((data: any) => {
console.log('SignalR Connected with: ' + data.transport.name);
this.connectionEstablished.emit(true);
this.connectionExists = true;
})
.fail((error: any) => {
console.log('SignalR could not connect: ' + error);
this.connectionEstablished.emit(false);
});
}
private registerOnServerEvents() {
this.proxy.on('listUpdated', (list: any) => {
console.log(list);
this.messageReceived.emit(list);
});
}
}
initialize(proxyName) gets called from a controller to start a connection to the Hub.
UPDATE
I've tried to rebuild the server and Hub using .NET Core 2.0, but when I test that on the IIS server I get:
"Failed to load https://signalr.example.com/online/negotiate: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'https://example.com' is therefore not allowed access."
So it's still a CORS issue even though I've setup everything just as multiple guides have done.
I've had issues in the past where the api path you are trying to hit is actually a virtual directory, and then IIS returns you a 403 because it thinks you are trying to view / access that directory instead of the webAPI route.
GET api/negotiate will 403 if you have the directory api/negotiate on your server.
This will be the case if you WebApiController is located in your project in a directory like:
/api/negotiate/NegotiateApiController.cs
You can resolve this very easily if that's the case by either changing the route or the directory name.
Note: This will come back as a 405 on some browsers.

Laravel 5 Validation - Return as json / ajax

I am trying to post the values into validation and return the response as json rather than return view as given in the documentation.
$validator = Validator::make($request->all(), [
'about' => 'min:1'
]);
if ($validator->fails()) {
return response()->json(['errors' => ?, 'status' => 400], 200);
}
The post is made by ajax so I need to receive the response in the ajax as well.
I figured out that in order to prevent refresh of the page in the returning response, I have to give it a status code of 200 outside the array. But I couldn't figure out what to give the 'errors' part. What should I write in there?
You can use $validator->messages() that returns an array which contains all the information about the validator, including errors. The json function takes the array and encodes it as a json string.
if ($validator->fails()) {
return response()->json($validator->messages(), Response::HTTP_BAD_REQUEST);
}
Note: In case of validation errors, It's better not to return response code 200. You can use other status codes like 400 or Response::HTTP_BAD_REQUEST
You can also tell Laravel you want a JSON response. Add this header to your request:
'Accept: application/json'
And Laravel will return a JSON response.
In Laravel 5.4 the validate() method can automatically detect if your request is an AJAX request, and send the validator response accordingly.
See the documentation here
If validation fails, a redirect response will be generated to send the user back to their previous location. The errors will also be flashed to the session so they are available for display. If the request was an AJAX request, a HTTP response with a 422 status code will be returned to the user including a JSON representation of the validation errors.
So you could simply do the following:
Validator::make($request->all(), [
'about' => 'min:1'
])->validate();
I use below this code for API in my existing project.
$validator = Validator::make($request->all(), [
'ride_id' => 'required',
'rider_rating' => 'required',
]);
if ($validator->fails()) {
return response()->json($validator->errors(), 400);
}
in case you are using a request class.
you may use failedValidation to handle you failed
/**
* Returns validations errors.
*
* #param Validator $validator
* #throws HttpResponseException
*/
protected function failedValidation(Validator $validator)
{
if ($this->wantsJson() || $this->ajax()) {
throw new HttpResponseException(response()->json($validator->errors(), 422));
}
parent::failedValidation($validator);
}
For those who have created a custom request class can override the public function response(array $errors) method and return a modified response without Validator explicitly.
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Http\JsonResponse;
class CustomRequest extends FormRequest
{
public function rules()
{
$rules = [
//custom rules
];
return $rules;
}
public function response(array $errors)
{
return new JsonResponse(['error' => $errors], 400);
}
}
My solution is to make my own FormRequest class which I put in the root API namespace namespace App\Http\Requests\Api.
Hope this helps someone
https://jamesmills.co.uk/2019/06/05/how-to-return-json-from-laravel-form-request-validation-errors/
Actually I used #Soura solution but with a little change. You need to import the Validator package as well.
$validator = \Validator::make($request->all(), [
'ride_id' => 'required',
'rider_rating' => 'required',
]);
if ($validator->fails()) {
return response()->json($validator->errors(), 400);
}

Angularjs, JavaEE and http request with inherited objects?

I work on webapp and can't find solution or example of my problem.
I use AngularJS, RestServis and JavaEE . My problem is how to send inherited object with superObject
In java I have two classes:
public class User{
protected String userName;
protected String userSurename;
..
..
}
Second class is a subclass
public class Worker extends User{
protected int idWorker;
protected String position;
..
..
}
in Angular controller I have
$scope.user = {
userName : "jon" ,
userSurename :"dep" }
$scope.worker= {
idWorker: 88 ,
position: "seller" }
and I use http protocol to send data on server side like this
this.saveWorker = function(worker) {
return $http({
method:'post',
url:this.apiBasicUrl,
contentType: "application/json",
data: worker
});
};
How in Angular in data to put one object and on Java side get worker object with user data also ? Can I , object like in java , make in angular with inherited ?
On Angular side, I suggest using $resource for communication with REST API:
var Worker = $resource('/worker/:workerId', {workerId:'#id'});
//get
var worker = Worker.get({workerId:123}, function() {
worker.abc = true;
//save
worker.$save();
});
On server side you should have a REST endpoint that is supposed to pick up these objects:
#Path("/worker")
public class WorkerService {
#GET
#Path("{workerId}")
public Worker getWorker(#PathParm("workerId") Integer workerId) {
//implement
}
#POST
public void saveWorker(Worker worker) {
//implement
}
}
This might not work out of the box. You will most likely need Jackson provider to enable REST to "translate" JSON into Java objects.
See this example: http://www.mkyong.com/webservices/jax-rs/json-example-with-jersey-jackson/

Categories

Resources