How to resolve access control in Rails? - angularjs

I am trying to send a post request to my rails api using angular js post request but I am getting this error :
XMLHttpRequest cannot load http://localhost:3000/api/v1/dis_generics. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:9000' is therefore not allowed access. The response had HTTP status code 404.
I am trying to find a way how to send a post request using angular to rails api . My controller in rails is like this :
class DisGenericsController < ApplicationController
before_action :set_dis_generic, only: [:show, :edit, :update, :destroy]
skip_before_action :verify_authenticity_token
# GET /dis_generics
# GET /dis_generics.json
def index
# #dis_generics = DisGeneric.all
respond_to do |format|
format.html
format.json { render json: DisGenericDatatable.new(view_context) }
end
end
# GET /dis_generics/1
# GET /dis_generics/1.json
def show
end
# GET /dis_generics/new
def new
#dis_generic = DisGeneric.new
end
# GET /dis_generics/1/edit
def edit
end
# POST /dis_generics
# POST /dis_generics.json
def create
#dis_generic = DisGeneric.new(dis_generic_params)
respond_to do |format|
if #dis_generic.save
format.html { redirect_to #dis_generic, notice: 'Dis generic was successfully created.' }
format.json { render :show, status: :created, location: #dis_generic }
else
format.html { render :new }
format.json { render json: #dis_generic.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /dis_generics/1
# PATCH/PUT /dis_generics/1.json
def update
respond_to do |format|
if #dis_generic.update(dis_generic_params)
format.html { redirect_to #dis_generic, notice: 'Dis generic was successfully updated.' }
format.json { render :show, status: :ok, location: #dis_generic }
else
format.html { render :edit }
format.json { render json: #dis_generic.errors, status: :unprocessable_entity }
end
end
end
# DELETE /dis_generics/1
# DELETE /dis_generics/1.json
def destroy
#dis_generic.destroy
respond_to do |format|
format.html { redirect_to dis_generics_url, notice: 'Dis generic was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_dis_generic
#dis_generic = DisGeneric.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def dis_generic_params
params.require(:dis_generic).permit(:name, :is_combination, :rxcui, :status_id, :food_id, :hepatic_id, :renal_imp_id, :release_status_id, :is_essential)
end
end
and this is my angular request :
var req = {
method: 'POST',
url: 'http://localhost:3000/api/v1/dis_generics',
headers: {
"Content-Type": "application/json"
},
data: {}
}
$http(req).success(function(data, status, header, config) {
alert( "failure message: " + JSON.stringify({data: data}));
});
This is my application controller :
class ApplicationController < ActionController::Base
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
include StaticPagesHelper
skip_before_filter :verify_authenticity_token
before_filter :cors_preflight_check
after_filter :cors_set_access_control_headers
protect_from_forgery unless: -> { request.format.json? }
def cors_set_access_control_headers
headers['Access-Control-Allow-Origin'] = '*'
headers['Access-Control-Allow-Methods'] = 'POST, GET, OPTIONS'
headers['Access-Control-Allow-Headers'] = '*'
headers['Access-Control-Max-Age'] = "1728000"
end
# If this is a preflight OPTIONS request, then short-circuit the
# request, return only the necessary headers and return an empty
# text/plain.
def cors_preflight_check
if request.method == :options
headers['Access-Control-Allow-Origin'] = '*'
headers['Access-Control-Allow-Methods'] = 'POST, GET, OPTIONS'
headers['Access-Control-Allow-Headers'] = '*'
headers['Access-Control-Max-Age'] = '1728000'
render :text => '', :content_type => 'text/plain'
end
end
end

You need to add access-control header in your rails app OR you can just change the method to 'JSONP' as per this thread: AngularJS: No "Access-Control-Allow-Origin" header is present on the requested resource
var req = {
method: 'JSONP',
url: 'http://localhost:3000/api/v1/dis_generics',
headers: {
"Content-Type": "application/json"
},
data: {}
}
$http(req).success(function(data, status, header, config) {

Related

Cross-Origin Request Blocked and Preflight executes View Django-project

In my Django and React project, I am trying to make a registration request which is failing due to a missing "Access-Control-Allow-Origin" header, resulting in a 504 error. The problem I believe I am facing is that the preflight (OPTIONS) request is already executing the View, which is causing issues with permissions for the subsequent POST request.
Jan 21 10:11:20 AllKids python3[155868]: [21/Jan/2023 09:11:20] "OPTIONS /user/register/ HTTP/1.0" 200 0
Jan 21 10:11:20 AllKids python3[155868]: in View
I am not sure why this issue is only occurring on this View, as all other views are working correctly.
Jan 21 10:21:40 AllKids python3[156001]: [21/Jan/2023 09:21:40] "POST /user/validatePassword/ HTTP/1.0" 200 613
It is worth noting that the OPTIONS request is returning a 200 status code. I would like to share the following code with you for further analysis:
let formData = {
password: password,
username: username,
email: email,
};
console.log(formData);
let request = await fetch(
`${process.env.REACT_APP_BACKEND_URL}/user/register/`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(formData),
}
);
console.log(response, 'WTF');
let response = await request.json();
The "WTF" line is not being reached since I am not getting the response... For comparison, here is an function that works perfectly fine(login):
let formData = { password: password, email: email };
let request = await fetch(
`${process.env.REACT_APP_BACKEND_URL}/user/validatePassword/`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(formData),
}
);
let response = await request.json();
here are my Django settings:
INSTALLED_APPS = [
...
"corsheaders",
]
MIDDLEWARE = [
'corsheaders.middleware.CorsMiddleware',
'django.middleware.security.SecurityMiddleware',
'whitenoise.middleware.WhiteNoiseMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
CORS_ORIGIN_ALLOW_ALL = True
here is the View which is being executed on the preflight request:
#api_view(["POST"])
def registerUser(request):
print("In Function")
body = returnContent(request)
try:
CustomUser.objects.get(email=body["email"])
return Response("Email already in use!")
except:
if len(body["username"]) < 4:
return Response("Username should be at least 3 characters long.")
if body["username"][0].isdigit():
return Response("Username should not start with a digit.")
if len(body["password"]) < 7:
return Response("Password must be at least 6 characters")
randomToken = random.randrange(100000, 999999)
user = CustomUser.objects.create_user(
username=body["username"], email=body["email"], password=body["password"], currentVerificationToken=randomToken)
sendEmailVerification(
user.username, user.currentVerificationToken, user.email)
user = CustomUserLoggedSerializer(user, many=False)
return Response(user.data)
and this would be the login request where everything works just fine...:
#api_view(["POST"])
def validatePassword(request):
body = returnContent(request)
try:
password = body["password"]
email = body["email"]
except:
return Response("No Email or Password provided")
try:
user = CustomUser.objects.get(email=email)
except:
return Response("Invalid email")
user = authenticate(request, email=email, password=password)
if user is not None:
if user.twoFactorVerification:
setattr(user, "currentVerificationToken",
random.randrange(100000, 999999))
user.save()
sendEmailVerification(
user.username, user.currentVerificationToken, user.email)
return Response("Two-Factor Authentication Required")
login(request, user)
user = CustomUserLoggedSerializer(user, many=False)
return Response(user.data)
else:
return Response(False)

React POST request to Django Rest ManyToMany field

What I want to do is post a ListLink object, which contains Link objects, to the database.
The Link objects are added by input field by the user and stored in the state until a request is sent for them to be saved in the database.
I am trying to make a post request to DRF, but I am getting the following response:
"Invalid data. Expected a dictionary, but got list."
I am using axios to make the request:
Home.jsx
handleSave = event => {
event.preventDefault();
return axios({
method: 'post',
url: 'http://localhost:8000/api/lists/',
headers: {
'Authorization': 'Token ' + localStorage.getItem('token')
},
data: {
links: this.state.links,
name: this.state.listName
}})
.then(res => {
console.log(res);
});
}
This is the state I am using to save the lists in:
this.state = {
listName: 'Link List',
listDescription: 'Add description here',
listURL: '',
currentLink: 'https://www.example.com',
links: []
};
Here are my models and serializers:
LinkList
class LinkList(models.Model):
owner = models.ForeignKey(
User,
related_name='lists',
on_delete=models.CASCADE)
name = models.CharField(max_length=100)
description = models.CharField(max_length=250)
public = models.BooleanField(default=False)
links = models.ManyToManyField(
Link,
related_name='linklists')
def __str__(self):
return "%s - %s" % (self.owner, self.name)
def save(self, *args, **kwargs):
super().save(*args, **kwargs)
Serializer:
class LinkListSerializer(serializers.ModelSerializer):
url = serializers.HyperlinkedIdentityField(view_name="lists-detail")
owner = serializers.ReadOnlyField(source='owner.username')
links = LinkSerializer()
class Meta:
model = LinkList
fields = ['url', 'owner', 'name', 'public', 'links']
Link
class Link(models.Model):
link = models.URLField(max_length=200)
def __str__(self):
return "%s" % (self.link)
Serializer:
class LinkSerializer(serializers.ModelSerializer):
class Meta:
model = Link
fields = ['url', 'link']
You can try to add many=True parameter to LinkSerializer but you will need to handle this list yourself (pop links attribute and manually create every link object).
class LinkListSerializer(serializers.ModelSerializer):
...
def create(self, validated_data):
with transaction.atomic(): # optional - ensure that changes will be rolled back on error
links = validated_data.pop('links', [])
instance = super().create(validated_data)
for l in links:
instance.links.create(link=l)
return instance

Axios post request is being denied by flask made api. CORS error coming up [duplicate]

This question already has an answer here:
cors enable in Request header field Access-Control-Allow-Origin is not allowed by Access-Control-Allow-Headers in preflight response
(1 answer)
Closed 2 years ago.
I am trying to add user from my react application through an API made with flask. But the post request is getting in error with the following error.
'http://localhost:5000/api/v1.0/add' from origin 'http://localhost:3000' has been blocked by CORS policy: Request header field access-control-allow-origin is not allowed by Access-Control-Allow-Headers in preflight response.
my axios code is following
const params = {
user_name : '5678234121',
passwd : 'password',
location : 'Kolkata',
pin_code : '700019',
secret_ques: 'What is your mother s maiden name?',
answr : 'aba',
status : 'Active',
remarks : 'test data'
};
const res = await Axios.post(
'http://localhost:5000/api/v1.0/add', params, {
headers: {
'content-type': 'application/json',
'Access-Control-Allow-Origin' : '*',
'Access-Control-Allow-Methods' : 'GET,PUT,POST,DELETE,PATCH,OPTIONS',
},
});
console.log(res.data);
my flask code is following
#app.route('/api/v1.0/add', methods=["POST"])
def add():
con = None
db = datadir + datafile
try:
_json = request.json
_name = _json['user_name']
_psswd = _json['passwd']
_locatn = _json['location']
_pincd = _json['pin_code']
_secrt = _json['secret_ques']
_ans = _json['answr']
_stat = _json['status']
_remks = _json['remarks']
# validate the received values
if _name and _psswd and _pincd and request.method == 'POST':
#do not save password as a plain text
_hashed_password = base64.b64encode(_psswd.encode("utf-8"))
# save edits
sql = '''INSERT INTO user_mast(user_name, passwd, location, pin_code, secret_ques, answr, status, remarks ) VALUES (?, ?, ?, ?, ?, ?, ?, ?)'''
data = (_name, _hashed_password.decode('ASCII'), _locatn, _pincd, _secrt,_ans, _stat, _remks , )
con = sqlite3.connect( db ) # Connection to database
cur = con.cursor()
cur.execute(sql, data)
con.commit()
resp = jsonify({'Status' : 'User added successfully!'})
resp.status_code = 200
else :
resp = jsonify ({'Status' :'Mandatory fields: Name,Password,Pincode missing..'})
resp.status_code = 502
except sqlite3.Error as e:
resp = jsonify({'Status' :'Database Error'})
resp.status_code = 500
except Exception as e:
print(e)
resp = jsonify({'Status' :'Unknown Error : Contact Administrator'})
resp.status_code = 501
finally:
cur.close()
con.close()
return resp
Please help me to fix the error, going clueless about this.
If you're new to this, I'd recommend just adding Flask-CORS to your application and not futzing around with the headers.

Django request.user is becoming empty after login using angularjs

I have Django and angularjs app running separately. I am able to login to system by using angularjs. however after login request.user in django gives empty data.
MIDDLEWARE_CLASSES = [
'corsheaders.middleware.CorsMiddleware',
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
CORS_ALLOW_CREDENTIALS = True
CORS_ORIGIN_ALLOW_ALL = True
Login code:
#csrf_exempt
def login_for_new_design(request, *args, **kwargs):
if request.method == "POST":
temp=json.loads(request.body)
username = temp.get("username", None)
password = temp.get("password", None)
user = authenticate(username=username, password=password)
response_data = {}
if user:
login(request, user)
response_data['success'] = True
response_data['message'] = 'Login was succesfull!'
else: # invalid case
response_data['success'] = True
response_data['message'] = 'Login was Failure!'
response = HttpResponse(json.dumps(response_data));
response["Access-Control-Allow-Origin"] = "*"
response["Access-Control-Allow-Methods"] = "POST, GET, OPTIONS"
response["Access-Control-Max-Age"] = "1000"
response["Access-Control-Allow-Headers"] = "*"
return response
ajax method:
$http({
method:'POST',
url:uri,
datatype:"json",
data:payload,
headers: {
'Content-Type': undefined
},
}).then(function(result){
console.log(result)
localStorage.setItem("username", $scope.username);
$state.go('app.main', {showLeftnav: true});
},function(error){
console.log(error)
})
Above two methods works fine.
But when I want test for if user is logged in or not using below method,
#csrf_exempt
def isAuthenticated_user(request):
userdic = {};
userdic['username'] = request.user.username
print userdic
response = HttpResponse(json.dumps(userdic));
response["Access-Control-Allow-Origin"] = "*"
response["Access-Control-Allow-Methods"] = "POST, GET, OPTIONS"
response["Access-Control-Max-Age"] = "1000"
response["Access-Control-Allow-Headers"] = "*"
return response
var csrftoken = $cookies.get('csrftoken')
authPromise = $http({
'method': "POST",
'url': "http://localhost:8000/isAuthenticated_user/",
headers:{
"X-CSRFToken": csrftoken,
'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8'
// 'withCredentials':true
},
})
request.user gives empty data.
Kindly let me know where I am doing wrong.
try,
user = self.request.query_params.get('username',None)
print user
let me know if some error occured

Why does AngularJS read integer `3` returned by DRF API as `%203`?

This is my DRF view which gets called at /posts/{id}:
class PostViewSet(mixins.CreateModelMixin, mixins.ListModelMixin, mixins.RetrieveModelMixin, mixins.DestroyModelMixin, GenericViewSet):
serializer_class = PostSerializer
permission_classes = (IsAuthenticated, IsActualOwnerDelete,)
def get_queryset(self):
# new posts from location.
return Post.objects.filter(location=self.request.user.userextended.location).order_by('-createdAt')
def perform_create(self, serializer):
serializer.save(actualOwner=self.request.user)
#list_route(permission_classes=[IsAuthenticated])
def mymostrecent(self, request):
me = request.user
try:
# this gets the most recent post's ID
post = me.post_mine_set.latest('id')
did = post.id
except Post.DoesNotExist:
did = 0
return Response(did)
Now with Angular, when I do to the URL /posts/mymostrecent:
return $http.get("/api/posts/mymostrecent")
.then(function(response) {
console.log(response);
$location.url('/posts/ ' + response.data);
})
What gets logged is this:
Object {data: 3, status: 200, config: Object, statusText: "OK"}
But the URL becomes this:
/posts/%203
It still works and shows the correct html page, but how do I get rid of the %20 in the URL?
This is my models.py (probably not needed):
class Post(models.Model):
owner = models.ForeignKey(User)
usersVoted = models.ManyToManyField(User, blank=True, related_name="%(class)s_voted_set")
post = models.CharField(max_length=400)
createdAt = models.DateTimeField(auto_now_add=True, blank=True)
actualOwner = models.ForeignKey(User, related_name="%(class)s_mine_set")
The problem is with this part of code, You are adding a extra space in this line $location.url('/posts/ ' + response.data);
return $http.get("/api/posts/mymostrecent")
.then(function(response) {
console.log(response);
$location.url('/posts/' + response.data); #Removed the space after '/posts/ ' ie. change '/posts/ ' to '/posts/'
})

Resources