I have a Django app that's using corsheaders package and its in settings.py like this:
INSTALLED_APPS = [ ..., corsheaders, ...]
...
MIDDLEWARE = [
# on top
"corsheaders.middleware.CorsMiddleware",
"django.middleware.common.CommonMiddleware",
...
]
...
CORS_ORIGIN_ALLOW_ALL = True
CORS_ALLOW_CREDENTIALS = True
When I'm trying to do a PATCH request on Google Chrome after the OPTIONS method I get this:
The Access-Control-Allow-Methods is missing PATCHand the next request fails with CORS methods error.
But I tried the same method on Firefox and its working as intended.
Seems like you need to set allowed origins explicitly, not by using the wildcard i.e. *:
CORS_ALLOWED_ORIGINS = [
"https://example.com",
"https://sub.example.com",
"http://localhost:8080",
"http://127.0.0.1:9000"
]
Also, set all HTTP verbs:
CORS_ALLOW_METHODS = [
'DELETE',
'GET',
'OPTIONS',
'PATCH',
'POST',
'PUT',
]
Read more:
https://pypi.org/project/django-cors-headers/
Chrome Cross-Domain PATCH request not working
CORS_ALLOW_ALL_ORIGINS = True or CORS_ORIGIN_ALLOW_ALL = True (OLD name) is equal to using wildcard * : L131 django-cors-headers middleware.py file
Related
So I deployed a Django-Rest/React app on Heroku where I serve my static and media files on AWS S3 buckets.
After pushing to Heroku and accessing the API URL or admin URL everything works fine but when I try to access my React URLs I get a MIME type error.
On the network tab of developer tools, I get status 301 on my JS and CSS file.
And in the console I get:
Refused to apply style from 'https://app.herokuapp.com/static/css/main.9d3ee958.css/' because its MIME type
('text/html') is not a supported stylesheet MIME type, and strict MIME checking is
enabled.
app.herokuapp.com/:1 Refused to apply style from 'https://app.herokuapp.com/static/css/main.9d3ee958.css/' because its MIME type
('text/html') is not a supported stylesheet MIME type, and strict MIME checking is
enabled.
app.herokuapp.com/:1 Refused to execute script from 'https://app.herokuapp.com/static/js/main.3b833115.js/' because its MIME type
('text/html') is not executable, and strict MIME type checking is enabled.
Even though the URL above is correct and I do have those files in my bucket.
Here are my production settings:
from decouple import config
import django_heroku
import dj_database_url
from .base import *
SECRET_KEY = config('SECRET_KEY')
DEBUG = False
ALLOWED_HOSTS = ['*']
ROOT_URLCONF = 'portfolio.urls_prod'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [
os.path.join(BASE_DIR, 'frontend/build')
],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
# DATABASE
DATABASES = {}
DATABASES['default'] = dj_database_url.config(conn_max_age=600)
# HEROKU
django_heroku.settings(locals())
# AWS S3 SETTINGS
AWS_ACCESS_KEY_ID = config('AWS_ACCESS_KEY_ID')
AWS_SECRET_ACCESS_KEY = config('AWS_SECRET_ACCESS_KEY')
AWS_STORAGE_BUCKET_NAME = config('AWS_STORAGE_BUCKET_NAME')
AWS_S3_CUSTOM_DOMAIN = '%s.s3.amazonaws.com' % AWS_STORAGE_BUCKET_NAME
AWS_DEFAULT_ACL = 'public-read'
AWS_S3_OBJECT_PARAMETERS = {
'CacheControl': 'max-age=86400',
}
AWS_HEADERS = {
'Access-Control-Allow-Origin': '*',
}
AWS_QUERYSTRING_AUTH = False
# AWS STATIC SETTINGS
AWS_LOCATION = 'static'
STATIC_URL = 'https://%s/%s/' % (AWS_S3_CUSTOM_DOMAIN, AWS_LOCATION)
STATICFILES_STORAGE = 'portfolio.storage_backend.StaticStorage'
# AWS MEDIA SETTINGS
DEFAULT_FILE_STORAGE = 'portfolio.storage_backend.MediaStorage'
MEDIA_URL = 'https://%s/%s/' % (AWS_S3_CUSTOM_DOMAIN, 'media')
STATICFILES_DIRS = [
os.path.join(BASE_DIR, 'frontend/build/static'),
]
# HEROKU LOGGING
DEBUG_PROPAGATE_EXCEPTIONS = True
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'formatters': {
'verbose': {
'format' : "[%(asctime)s] %(levelname)s [%(name)s:%(lineno)s] %(message)s",
'datefmt' : "%d/%b/%Y %H:%M:%S"
},
'simple': {
'format': '%(levelname)s %(message)s'
},
},
'handlers': {
'console': {
'level': 'DEBUG',
'class': 'logging.StreamHandler',
},
},
'loggers': {
'MYAPP': {
'handlers': ['console'],
'level': 'DEBUG',
},
}
}
# HTTPS SETTING
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True
SECURE_SSL_REDIRECT = True
# HSTS SETTINGS
SECURE_HSTS_SECONDS = 31536000 # 1 year
SECURE_HSTS_PRELOAD = True
SECURE_HSTS_INCLUDE_SUBDOMAINS = True
options = DATABASES['default'].get('OPTIONS', {})
options.pop('sslmode', None)
This is my storage_backend.py code:
from storages.backends.s3boto3 import S3Boto3Storage
class MediaStorage(S3Boto3Storage):
location = 'media'
file_overwrite = False
class StaticStorage(S3Boto3Storage):
location = 'static'
default_acl = 'public-read'
This is my url_prod.py code:
from django.contrib import admin
from django.urls import path, re_path, include
from django.views.generic import TemplateView
from django.conf import settings
from django.conf.urls.static import static
urlpatterns = [
path("admin/", admin.site.urls),
path('api/', include('api.urls')),
re_path(r'^(?P<path>.*)/$', TemplateView.as_view(template_name='index.html')),
path('', TemplateView.as_view(template_name='index.html')),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
This is my bucket policy:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowPublicRead",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::bucket-name/*"
}
]
}
EDIT:
I checked the network tab in developer tools and realized that my staticfiles from admin are being served from my was bucket:
Request URL:
https://bucket-name.s3.amazonaws.com/static/admin/css/base.css
Request Method: GET
Status Code: 200 OK (from disk cache)
Remote Address: 52.95.143.47:441
Referrer Policy: same-origin
But the static files for my React views are not:
Request URL:
https://app.herokuapp.com/static/css/main.9d3ee958.css
Request Method: GET
Status Code: 301 Moved Permanently
Remote Address: 54.224.34.30:441
Referrer Policy: same-origin
So I decided to answer my own question in case someone sees this and has the same problem.
The problem was whenever I ran "npm run build", React was creating my index.html with both js and CSS files linked to my local path in the build folder.
So after a lot of research, I decided to create a .env file in the root directory of my react app with this setting:
PUBLIC_URL=https://path-to-bucket.s3.amazonaws.com
Now every time I run build react will add this URL to "src" in both my js and CSS files.
Check documentation here.
Before adding this setting:
<html lang="en">
<head>
<script defer="defer" src="../static/js/main.d91dacb2.js"></script>
<link href="../static/css/main.9d3ee958.css" rel="stylesheet" />
</head>
<body>
<div id="root"></div>
</body>
After adding this setting:
<html lang="en">
<head>
<script defer="defer" src="https://path-to-bucket.s3.amazonaws.com/static/js/main.d91dacb2.js"></script>
<link href="https://path-to-bucket.s3.amazonaws.com/static/css/main.9d3ee958.css" rel="stylesheet" />
</head>
<body>
<div id="root"></div>
</body>
But my images where still not loading so I decided to create a function that checked if the app was running in development or production and created an URL for each situation:
export const dynamicUrl = (name) => {
let url
if (!process.env.NODE_ENV || process.env.NODE_ENV === 'development') {
url = `../static/images/${name}`
} else {
url = `https://path-to-bucket.s3.amazonaws.com/static/images/${name}`
}
return url
};
NODE_ENV is a variable that comes with procces.env that checks the environment.
Hope this helps someone that has the same problem I did.
I have a React frontend app that needs to send a request to my Backend written in Django
My frontend and backend are now on the same domain but different subdomains.
But I'm getting some CORS problems, more specificly, CORS header ‘Access-Control-Allow-Origin is missing.
I found a lot of questions on stackoverflow on how you need to install django-cors-headers but it simply doesn't work for me.
my current backend configuration:
settings.py
INSTALLED_APPS = [
...,
"corsheaders",
...,
]
MIDDLEWARE = [
'corsheaders.middleware.CorsMiddleware',
'debug_toolbar.middleware.DebugToolbarMiddleware',
'django.middleware.security.SecurityMiddleware',
'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',
'django.middleware.locale.LocaleMiddleware',
'simple_history.middleware.HistoryRequestMiddleware',
]
ALLOWED_HOSTS = ["*"]
CORS_ALLOW_ALL_ORIGINS = True
views.py (where I create the api)
#csrf_exempt
#api_view(["GET"])
#permission_classes([AllowAny])
#xframe_options_exempt
def create_user_and_ci(request):
try:
# code to execute
return Response({"status": "Succes"}, status.HTTP_200_OK)
except:
return Response({"status": "Error"}, status.HTTP_500_INTERNAL_SERVER_ERROR)
And then on my frontend I execute this:
fetch("https://subdomain.mydomain/get/id", {
method: 'GET',
headers: {
'Authorization': `Token mytoken`,
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*'
// Other possible headers
}
}).then((res) => console.log(res));
UPDATE
When I make the call without giving the headers, it works, problem is I need to send my token to my backend for validation
Foremost, this CORS error is due to the fact that your frontend is not on the same domain as your Django API/Backend, so all the Django responses need to contain the CORS related headers here.
I found this post about adding a custom HTTP header with a middleware in Django, this might help you here.
Install this package:
pip install django-cors-headers
INSTALLED_APPS = [
...,
"corsheaders",
...,
]
CORS_ALLOWED_ORIGINS = [
http://127.0.0.1:3000, #For React Project
http://127.0.0.1:8000 #For Django Project
]
In MiddleWare add this in the list
MIDDLEWARE = [
"corsheaders.middleware.CorsMiddleware",]
I have running django backend on http://127.0.0.1:8000 and I want to request it with reactjs frontend.
As you can see below, I can see the successful response in the Insomnia app.
But, When I want a request with reactjs frontend, I get a CORS ERROR.
I check the request in the inspect networks and I saw a similar request payload with insomnia.
install django-cors-headers:
pip install django-cors-headers
Add corsheaders to INSTALLED_APPS in settings.py:
INSTALLED_APPS = [
...,
"corsheaders",
...,
]
Add CorsMiddleware to your middlewares in settings.py:
MIDDLEWARE = [
...,
"corsheaders.middleware.CorsMiddleware",
"django.middleware.common.CommonMiddleware",
...,
]
Now you can set your allowed origins in settings.py like this:
CORS_ALLOWED_ORIGINS = [
"https://example.com",
"https://sub.example.com",
"http://localhost:8080",
"http://127.0.0.1:9000",
]
More info in this link.
I'm trying to return the X-Frame-Options in my create react app (rewired) but I'm not sure of the correct syntax to use to add the function to my existing override. How do I do this properly?
module.exports = override(
fixBabelImports("react-bulma-components", {
libraryName: "react-bulma-components",
libraryDirectory: "lib/components"
}),
{devServer: function(configFunction) {
return function(proxy, allowedHost) {
const config = configFunction(proxy, allowedHost)
config.headers = {
'X-Frame-Options': 'Deny'
}
return config
}
}},
...addCompressions()
);
The front end is a CRA (rewired) non-static webapp
The backend is a node app hosted seperately
I've also tried changing the buildpack to this buildback in order to add the configuration in a static.json file, but that breaks a lot of different things, uses a different server etc.
The proper way of doing this, is by not doing it... is useless, dont waste your time. Let's remember that yow CRA Page will executed on the browser and it won't send you headers/data or anything, instead it will be send as well by Nginx/Apache/NodeJs something else.
Firefox even says the same: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options
Note: Setting X-Frame-Options inside the element is useless! For instance, has no effect. Do not use it! X-Frame-Options works only by setting through the HTTP header, as in the examples below.
Heroku
You can configure different options for your static application by writing a static.json in the root folder of your application.
Custom Headers
Using the headers key, you can set custom response headers. It uses the same operators for pathing as Custom Routes.
{
"headers": {
"/": {
"Cache-Control": "no-store, no-cache"
},
"/assets/**": {
"Cache-Control": "public, max-age=512000"
},
"/assets/webfonts/*": {
"Access-Control-Allow-Origin": "*"
}
}
}
https://blog.heroku.com/using-http-headers-to-secure-your-site
We have setup our development environment with webpack-dev-server. We use its proxy config to communicate with the backend.
We have a common login page in the server which we use in all our applications. We it is called, it sets a session cookie which expected to passed with subsequent requests. We have used the following config but the cookie is not set in the browser for some reason. I can see it in response header in the network tab of dev tool.
const config = {
devServer: {
index: "/",
proxy: {
"/rest_end_point/page": {
target: "https://middleware_server",
secure : false
},
"/": {
target: "https://middleware_server/app/login",
secure : false
},
}
The https://middleware_server/app/login endpoint returns the login page with the set-cookie header.
The proxy is used to avoid CORS errors when accessing login pages and API calls.
Upto this point no code from the application is executed. Do we have to do something in the coomon login page to get the cookie set?
the application is written with React.
Any help would be appreciated.
I have the same use case and this is what I have done.
In my case, I have multiple proxy targets so I have configured the JSON (ProxySession.json) accordingly.
Note: This approach is not dynamic. you need to get JSESSIONID manually(session ID) for the proxy the request.
login into an application where you want your application to proxy.
Get the JSESSIONID and add it in JSON file or replace directly in onProxyReq function and then run your dev server.
Example:
Webpack-dev.js
// Webpack-dev.js
const ProxySession = require("./ProxySession");
config = {
output: {..........},
plugins: [.......],
resolve: {......},
module: {
rules: [......]
},
devServer: {
port: 8088,
host: "0.0.0.0",
disableHostCheck: true,
proxy: {
"/service/**": {
target: ProxySession.proxyTarget,
changeOrigin: true,
onProxyReq: function(proxyReq) {
proxyReq.setHeader("Cookie", "JSESSIONID=" + ProxySession[buildType].JSESSIONID + ";msa=" + ProxySession[buildType].msa + ";msa_rmc=" + ProxySession[buildType].msa_rmc + ";msa_rmc_disabled=" + ProxySession[buildType].msa_rmc);
}
},
"/j_spring_security_check": {
target: ProxySession.proxyTarget,
changeOrigin: true
},
"/app_service/websock/**": {
target: ProxySession.proxyTarget,
changeOrigin: true,
onProxyReq: function(proxyReq) {
proxyReq.setHeader("Cookie", "JSESSIONID=" + ProxySession[buildType].JSESSIONID + ";msa=" + ProxySession[buildType].msa + ";msa_rmc=" + ProxySession[buildType].msa_rmc + ";msa_rmc_disabled=" + ProxySession[buildType].msa_rmc);
}
}
}
}
ProxySession.json
//ProxySession.json
{
"proxyTarget": "https://t.novare.me/",
"build-type-1": {
"JSESSIONID": "....",
"msa": "....",
"msa_rmc": ...."
},
"build-type-2": {
"JSESSIONID": ".....",
"msa": ".....",
"msa_rmc":"....."
}
}
I met the exact same issue, and fixed it by this way:
This is verified and worked, but it's not dynamic.
proxy: {
'/my-bff': {
target: 'https://my.domain.com/my-bff',
changeOrigin: true,
pathRewrite: { '^/my-bff': '' },
withCredentials: true,
headers: { Cookie: 'myToken=jx42NAQSFRwXJjyQLoax_sw7h1SdYGXog-gZL9bjFU7' },
},
},
To make it dynamic way, you should proxy to the login target, and append a onProxyRes to relay the cookies, something like: (not verified yet)
onProxyRes: (proxyRes: any, req: any, res: any) => {
Object.keys(proxyRes.headers).forEach(key => {
res.append(key, proxyRes.headers[key]);
});
},
"/api/**": {
...
cookieDomainRewrite: { "someDomain.com": "localhost" },
withCredentials: true,
...
}
You can use this plugin to securely manage auth cookies for webpack-dev-server:
A typical workflow would be:
Configure a proxy to the production service
Login on the production site, copy authenticated cookies to the local dev server
The plugin automatically saves your cookie to system keychain
https://github.com/chimurai/http-proxy-middleware#http-proxy-options
use option.cookieDomainRewrite and option.cookiePathRewrite now
cookies ??
devServer: {
https: true, < ------------ on cookies
host: "127.0.0.1",
port: 9090,
proxy: {
"/s": {
target: "https://xx < --- https
secure: false,
//pathRewrite: { "^/s": "/s" },
changeOrigin: true,
withCredentials: true
}
}
}
. . . . . . . . . . .