I am trying to access a django server using django-rest-framework from angular using the following service:
myapp.factory("GetData", ["$resource",function($resource) {
return $resource(
"http://local/path/**/users/:username/",
{},
{
"query": {
method: "GET",
isArray: true,
headers:{
"Content-Type":"application/json"
}
}
},
{
stripTrailingSlashes:false
}
);
}]);
When I put the URL in the browser, I get the desired output, but the problem is that when I try to access via Angular, in my console I am getting a 403 forbidden error. Can anyone explain to me whats causing this. and how I can possibly fix this issue.
My url.py looks as follows:
from rest_framework.routers import DefaultRouter
from .views import UserViewSet
router = DefaultRouter()
router.register(prefix='users', viewset=UserViewSet)
urlpatterns = router.urls
My views.py file is as follows:
from django.shortcuts import render
from django.http import HttpResponse
from rest_framework import viewsets
from .models import users
from .serializers import UserSerializer
class UserViewSet(viewsets.ModelViewSet):
queryset = users.objects.all()
serializer_class = UserSerializer
I think the 403 forbidden is coming to browser block cross origin requests.
You need to enable allow CORS at your API server by setting appropriate headers.
You can lookup https://github.com/ottoyiu/django-cors-headers
For this you need to add in your installed apps.
'corsheaders'
And just set to test it out. Check for fine tuned settings in the docs.
CORS_ORIGIN_ALLOW_ALL = True
Edit
Also you need to add this in your middlewares.
'corsheaders.middleware.CorsMiddleware',
I managed to fix the problem by combining what #Bipul Jain suggested https://stackoverflow.com/a/42044910/7210105 (above) and also altering this link in my $resource
"http://local/path/**/users/:username/"
I removed http://local/path from the link and the 403 forbidden error went away.
Related
I built a simple demo cinema management application with React.js and Flask.
The React movies component in which all the the cinema movies ( Fetched from Flask ) are displayed, works just fine - as long as I access the React url from the same computer (http://localhost:3000/movies ).
When I try to access React from another computer in my network, using the source computer IP which in my case is 10.0.0.14 ( http://10.0.0.14:3000/movies ), although React is working, I can't make axios API calls and I get the following error.
GET http://localhost:5000/movies net::ERR_CONNECTION_REFUSED
Uncaught (in promise) AxiosError {message: 'Network Error', name: 'AxiosError', code: 'ERR_NETWORK', config: {…}, request: XMLHttpRequest, …}
xhr.js:220 GET http://localhost:5000/movies net::ERR_CONNECTION_REFUSED
Now, This is the part of my React code from which requests are made
useEffect(() =>
{
async function getMovies()
{
let resp = await axios.get("http://localhost:5000/movies/");
setMovies;
}
getMovies()
},[])
This is my Flask code:
from flask import Flask
import json
from bson import ObjectId
from flask_cors import CORS
from routers.persons import persons
class JSONEncoder(json.JSONEncoder):
def default(self, obj) :
if isinstance(obj, ObjectId):
return str(obj)
return json.JSONEncoder.default(self,obj)
app = Flask(__name__)
CORS(app)
app.url_map.strict_slashes = False
app.json_encoder = JSONEncoder
app.register_blueprint(persons, url_prefix="/movies/")
app.run()
Can somebody tell me how to fix this and allow axios requests when accessing React from another device?
Check your API call of the react app. You are using localhost even you are doing the api call from a different host browser. Change the localhost to the api host ip then it will work.
Change this to http://localhost:5000/movies/ to http://<api-ip-address>:5000/movies/.
I am working on a project with Springboot ReactJS and MongoDB.
I have implemented the whole code but it doesn't import data from the database. It shows the below error.
Access to XMLHttpRequest at 'http://localhost:8080/api/auth/file' from origin 'http://localhost:8081' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
I go through the solutions I found through StackOverflow and tried the below ways to solve this,
Adding #crossorigin
Adding the chrome extension
npm install cors
But it still doesn't work.
I would be glad if anyone could help me to solve this issue.
Controller
package com.spring.mongodb.controllers;
import com.spring.mongodb.models.LogFile;
import com.spring.mongodb.models.LogRecord;
import com.spring.mongodb.models.LogRecordCollection;
import com.spring.mongodb.payload.request.BackupRequest;
import com.spring.mongodb.payload.request.DeleteFileRequest;
import com.spring.mongodb.repository.LogFileRepository;
import com.spring.mongodb.repository.LogRecordRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
import java.util.List;
#RestController
#CrossOrigin(origins = "http://localhost:8081")
#RequestMapping("/api/auth/file")
public class LogFileController {
#Autowired
LogFileRepository logFileRepository;
#Autowired private LogRecordRepository logRecordRepository;
#GetMapping("")
public ResponseEntity<?> getAllLogFiles() {
try{
List<LogFile> logFiles = logFileRepository.findAll();
return ResponseEntity.ok().body(logFiles);
}catch (Exception e){
return ResponseEntity.status(HttpStatus.EXPECTATION_FAILED).body(e.getMessage());
}
}
#DeleteMapping
public void deleteFiles(#Valid #RequestBody DeleteFileRequest request) {
List<String> recordIds = request.getRecordIds();
for (String recordId : recordIds) {
logFileRepository.deleteById(recordId);
LogRecordCollection collection = new LogRecordCollection();
collection.setCollectionName(recordId);
logRecordRepository.deleteAll();
}
}
}
Request sending from frontend
await axios
.get("http://localhost:8080/api/auth/file")
.then((res) => {
console.log(res);
this.setState({
folders: res.data,
});
})
.catch(function (error) {
console.log(error);
});
this.setState({
loading: true
})
You can try by adding the http component dependency and then give the cross origin value in controller class, You have to mentioned a link in cross origin from where your RESTfull api will get called
Dependency
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<scope>test</scope>
</dependency>`
Like below you can add the cross origin value in controller
#CrossOrigin(origins = "http://localhost:8081")
I use swagger-ui-react in my application. But I don't know how to config to add the authorization into api requests.
I had found an answer use in swagger ui from here:
window.swaggerUi = new SwaggerUi({...})
...
swaggerUi.api.clientAuthorizations.add("key", new SwaggerClient.ApiKeyAuthorization("Authorization", "Basic dXNlcm5hbWU6cGFzc3dvcmQ=", "header"));
But I don't know how to use in swagger-ui-react. Here is my code:
import styles from './index.less';
import React from 'react';
// tslint:disable
import SwaggerUI from 'swagger-ui-react';
import 'swagger-ui-react/swagger-ui.css';
// tslint:able
const SwaggerComp = params => {
const auth = params.authorization;
return (
<div className={styles.wrapper}>
<SwaggerUI
url="/v2/swagger-file-url"
withCredentials
/>
</div>
)
};
export default SwaggerComp;
To send the Authorization header in "try it out" requests, your API definition file (/v2/swagger-file-url) must define the appropriate security for operations. Users will need to click the "Authorize" button to enter the authentication information (such as the username and password for Basic auth) before doing "try it out".
OpenAPI 3.0 example:
openapi: 3.0.2
components:
securitySchemes:
basicAuth:
type: http
scheme: basic
security:
- basicAuth: []
OpenAPI 2.0 example:
swagger: '2.0'
securityDefinitions:
basicAuth:
type: basic
security:
- basicAuth: []
For more information, see:
Authentication guide for OpenAPI 3.0
Authentication guide for OpenAPI 2.0
In react-swagger-ui, they have a network property called requestInterceptor, in here you can modify the request json before passing it to the api call, so you can add the authorization header in there, and remember to return the modified json in requestInterceptor.
To set up the authentication header in the json, there are a couple ways to do it, I was using sigv4 for authorization header, and I used Amplify Signer to generator all the required header(Authorization, X-Amz-Date..) for me before the api call, this is the link here.
I'm currently having an issue that has been driving me crazy for the past 30-40 mins. I've successfully created a products api using Django/Django REST framework. But when I call the endpoint to try and consume it with angular, I get a 404 error. When I open the console I am greeted with an error that states GET http://localhost:8000/static/api/products/ 404 (Not Found). However, when I navigate to the URL manually in browser I get the browsable api menu.
I'm not exactly sure what's going on here...but I'm thinking it could be because of my angular static URLs/roots.
Here is the current code for the main area URLs of the app:
from django.conf.urls import url,include
from django.contrib import admin
from django.conf.urls.static import static
from django.conf import settings
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^api/', include('customerreview_rest.urls', namespace='api')),
url(r'^api/',include ('products_rest.urls', namespace='api')),
url(r'^', include('GemStore_App.urls',namespace='frontend')),
] + static(settings.MEDIA_URL,document_root = settings.MEDIA_ROOT)
Here is the products URL/root for the endpoint:
from django.conf.urls import url,include
from rest_framework import routers
from products_rest.viewsets import ProductsViewsets
router = routers.DefaultRouter()
router.register('products',ProductsViewsets,'products')
urlpatterns = [
url(r'^', include(router.urls)) #base router
]
Lastly, here is the code for the static angular files:
from django.conf.urls import url, include
from django.views.generic.base import RedirectView
urlpatterns = [
url(r'^$', RedirectView.as_view(url='static/index.html', permanent=False), name='index')
]
Here also, is the code I planed to use to consume the api using Angular:
myStore.controller("myStoreController",function($scope,$http){
$scope.gems = $http.get("api/products/").then(
function(response){
$scope.gems = response.data
}, function(error){
$scope.error = error
});
})
Any light that can be shed on this topic, or maybe a point in the right direction would be greatly appreciated.
Thanks
Turns out that the issue was that I needed to include a another / in my call in order for it to be accepted.
So in summary, the code for the angular portian looks like this now:
myStore.controller("myStoreController",function($scope,$http){
$scope.gems = $http.get("/api/products/").then(
function(response){
$scope.gems = response.data
}, function(error){
$scope.error = error
});
})
#Sayse Thanks for helping.
with the following code I am getting a 404 resource not found error after clicking authorize button for google drive. My code is below- any ideas what I am doing incorrectly?
from __future__ import print_function
import httplib2
import os
from apiclient import discovery
from oauth2client import client
from oauth2client import tools
from oauth2client.file import Storage
from apiclient.discovery import build
from google.appengine.ext import webapp
from oauth2client.appengine import OAuth2DecoratorFromClientSecrets
import webapp2
try:
import argparse
flags = argparse.ArgumentParser(parents=[tools.argparser]).parse_args()
except ImportError:
flags = None
except SystemExit:
flags= None
#
## If modifying these scopes, delete your previously saved credentials
## at ~/.credentials/drive-python-quickstart.json
SCOPES = 'https://www.googleapis.com/auth/drive'
CLIENT_SECRET_FILE = 'client_secret.json'
APPLICATION_NAME = 'Drive API Quickstart'
decorator = OAuth2DecoratorFromClientSecrets( CLIENT_SECRET_FILE,SCOPES)
service = build('drive', 'v3')
class MainHandler(webapp.RequestHandler):
#decorator.oauth_required
def get(self):
# Get the authorized Http object created by the decorator.
http = decorator.http()
# Call the service using the authorized Http object.
request = service.files().list(q = "mimeType != 'application/vnd.google-apps.folder'", pageSize=1000, )
response = request.execute(http=http)
app = webapp.WSGIApplication([
('/', MainHandler),
], debug=True)
I have https://drive-156701.appspot.com/oauth2callback with and without a / at the end as redirects, which I thought where the correct redirect urls?
Thanks!!
You don't have a URL handler for /oauth2callback. You only have a url handler for /. Try:
app = webapp.WSGIApplication([
('/oauth2callback', Oauth2CallbackHandler),
('/', MainHandler),
], debug=True)
and make a Oauth2CallbackHandler class to handle the callback.
In addition to including the :
app = webapp2.WSGIApplication(
[
('/', MainHandler),
(decorator.callback_path, decorator.callback_handler()),
],
debug=True)
The #decorator.oauth_required handles the callbacks for you.
Check out this video: https://www.youtube.com/watch?v=HoUdWBzUZ-M
You need to create credentials for both localhost development and deployed.
And make sure you have checked out: https://cloud.google.com/appengine/docs/standard/python/tools/using-libraries-python-27
Your api imports must be handled like 3rd party imports, details here:
https://developers.google.com/api-client-library/python/start/installation