Situation:
I am attempting build a full SPA using Vue.js as my front end and Django as my back end. These systems are entirely separate (not a hybrid app with the index.html page served by the back end).
Approach
I created a services directory in my Vue-CLI generated project that provides the general accessibility for my REST API via the api.js file (contents below):
import axios from "axios";
import Cookies from "js-cookie";
axios.defaults.xsrfHeaderName = "X-CSRFToken";
axios.defaults.xsrfCookieName = "csrftoken";
const BackEnd = "http://127.0.0.1:8000/"; //local backend from manage.py runserver
export default axios.create({
baseURL: `${BackEnd}api/`,
timeout: 5000,
headers: {
"Content-Type": "application/json",
"X-CSRFToken": Cookies.get('csrftoken')
}
});
How do I know there is such a token to get? I wrote an API endpoint that provides the token in the Response headers (shown below):
Access-Control-Allow-Origin: *
Content-Length: 77
Content-Type: application/json
Date: Sun, 19 Jul 2020 18:04:06 GMT
Server: WSGIServer/0.2 CPython/3.7.6
Set-Cookie: csrftoken=HdM4y6PPOB44cQ7DKmla7lw5hYHKVzTNG5ZZJ2PqAUWE2C79VBCJbpnTyfEdX3ke; expires=Sun, 18 Jul 2021 18:04:06 GMT; Max-Age=31449600; Path=/; SameSite=Lax
Vary: Cookie, Origin
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
Problem
While my Django REST Framework API is doing a create job serving up all the data for my GET requests, I cannot seem to assign the csrftoken properly to authenticate my POST requests. Even with the X-CSRFToken header appropriately set in my axios request, I still get the typical 403 (CSRF cookie not set) response from the server
Request Headers
Accept: application/json, text/plain, */*
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Connection: keep-alive
Content-Length: 247
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary9vOu1sBaQrXtXseR
DNT: 1
Host: 127.0.0.1:8000
Origin: http://127.0.0.1:8080
Referer: http://127.0.0.1:8080/
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-site
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.89 Safari/537.36
X-CSRFToken: T2Z7pzxKTAuCvBEIjkgRf8RGEEVLYfOyDYkYIcfkWCfSkPB76wCjMMizZvdTQPKg
UPDATE
Okay now this is just a pain! I've got a different token value in A) the Set-Cookie response header, B) the value for the csrftoken in my browser cookies, and C) in the axios POST request. Can anyone help me figure out what's going on here?
Django
you need youse djoser in django for authentication
wright
pip install djangorestframework-simplejwt
pip install djoser
settings.py changes
Add djoser in your INSTALLED_APPS
INSTALLED_APPS=[
...,
'djoser',
...
]
Add in your MIDDLEWERE
MIDDLEWERE=[
...,
'django.contrib.auth.middleware.AuthenticationMiddleware',
...
]
Add
# DRF settings
REST_FRAMEWORK = {
# Default permissions
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.DjangoModelPermissionsOrAnonReadOnly',
],
# Token types
"DEFAULT_AUTHENTICATION_CLASSES": [
"rest_framework_simplejwt.authentication.JWTAuthentication",
"rest_framework.authentication.SessionAuthentication"
],
}
DJOSER = {
'PASSWORD_RESET_CONFIRM_URL':
'reset_password/{uid}/{token}',
'ACTIVATION_URL': 'activation/{uid}/{token}',
'SEND_ACTIVATION_EMAIL': True,
'SEND_CONFIRMATION_EMAIL': True,
'TOKEN_MODEL': None,
'HIDE_USERS': True,
'SERIALIZERS': {
},
'PERMISSIONS': {
'activation': ['rest_framework.permissions.AllowAny'],
'password_reset': ['rest_framework.permissions.AllowAny'],
'password_reset_confirm': ['rest_framework.permissions.AllowAny'],
'set_password': ['djoser.permissions.CurrentUserOrAdmin'],
'username_reset': ['rest_framework.permissions.AllowAny'],
'username_reset_confirm': ['rest_framework.permissions.AllowAny'],
'set_username': ['djoser.permissions.CurrentUserOrAdmin'],
'user_create': ['rest_framework.permissions.AllowAny'],
'user_delete': ['djoser.permissions.CurrentUserOrAdmin'],
'user': ['djoser.permissions.CurrentUserOrAdmin'],
'user_list': ['djoser.permissions.CurrentUserOrAdmin'],
'token_create': ['rest_framework.permissions.AllowAny'],
'token_destroy': ['rest_framework.permissions.IsAuthenticated'],
}
}
# JWT settings
SIMPLE_JWT = {
'ACCESS_TOKEN_LIFETIME': timedelta(days=2),
'REFRESH_TOKEN_LIFETIME': timedelta(days=5),
'ROTATE_REFRESH_TOKENS': False,
'BLACKLIST_AFTER_ROTATION': True,
'UPDATE_LAST_LOGIN': False,
'ALGORITHM': 'HS256',
'SIGNING_KEY': SECRET_KEY,
'VERIFYING_KEY': None,
'AUDIENCE': None,
'ISSUER': None,
'AUTH_HEADER_TYPES': ('JWT',),
'AUTH_HEADER_NAME': 'HTTP_AUTHORIZATION',
'USER_ID_FIELD': 'id',
'USER_ID_CLAIM': 'user_id',
'USER_AUTHENTICATION_RULE': 'rest_framework_simplejwt.authentication.default_user_authentication_rule',
'AUTH_TOKEN_CLASSES': ('rest_framework_simplejwt.tokens.AccessToken',),
'TOKEN_TYPE_CLAIM': 'token_type',
'JTI_CLAIM': 'jti',
'SLIDING_TOKEN_REFRESH_EXP_CLAIM': 'refresh_exp',
'SLIDING_TOKEN_LIFETIME': timedelta(days=2),
'SLIDING_TOKEN_REFRESH_LIFETIME': timedelta(days=5),
}
In your app urls.py add djoser urls
urlpatterns = [
# DRF router
path('', include(router.urls)),
# djoser auth urls
url(r'^auth/', include('djoser.urls')),
# djoser auth jwt urls
url(r'^auth/', include('djoser.urls.jwt')),
# Login GUI DRF
path('api-auth/', include('rest_framework.urls', namespace='rest_framework')),
]
Vue
Base API URL
project/src/api/common.js
import axios from 'axios'
export const HTTP = axios.create({
baseURL: 'http://api-url',
})
Base element project/src/api/element.js
import {HTTP} from './common'
function createHTTP(url) {
return {
async post(config) {
return HTTP.post(`${url}`, config).then(response => {
console.log(response)
return response.data
})
},
async get(element) {
return HTTP.get(`${url}${element.id}/`)
},
async patch(element) {
console.log(element)
return HTTP.patch(`${url}${element.id}/`, element).then(response => {
console.log(response)
return response.data
})
},
async delete(id) {
HTTP.delete(`${url}${id}/`)
return id
},
async list(queryParams = '') {
return HTTP.get(`${url}${queryParams}`).then(response => {
return response.data.results
})
}
}
}
export const Todos = createHTTP(`/todos/`)
Your store project/src/store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
import todos from "#/store/modulse/todos";
Vue.use(Vuex)
export default new Vuex.Store({
modules: {
todos,
}
})
Your mutations types project/src/store/mutation-types.js
export const SET_TODOS ='SET_TODOS'
export const PATCH_TODO ='PATCH_TODO'
export const DELETE_TODO ='DELETE_TODO'
export const CREATE_TODO ='CREATE_TODO'
Your module project/src/store/modulse/todos.js
import {
Todos,
} from '#/api/elements'
import {
SET_TODOS, PATCH_TODO, DELETE_TODO, CREATE_TODO
} from '../mutation-types'
// Getters
export default {
state: {
todos: []
},
getters: {
getTodos(state) {
return state.todos
},
},
// Mutations
mutations: {
[SET_TODOS](state, todos) {
state.todos = todos
},
[PATCH_TODO](state, todos) {
let id = todos.id
state.todos.filter(todos => {
return todos.id === id
})[0] = todos
},
[CREATE_TODO](state, todo) {
state.todos = [todo, ...state.todos]
},
[DELETE_TODO](state, {id}) {
state.todos = state.todos.filter(todo =>{
return todo.id !==id
})
},
},
// Actions
actions: {
async setTodos({commit}, queryParams) {
await Todos.list(queryParams)
.then(todos => {
commit(SET_TODOS, todos)
}).catch((error) => {
console.log(error)
})
},
async patchTodo({commit}, todoData) {
await Todos.patch(todoData)
.then(todo => {
commit(PATCH_TODO, todo)
}).catch((error) => {
console.log(error)
})
},
async deleteTodo({commit}, todo_id) {
await Todos.delete(todo_id)
.then(resp => {
commit(DELETE_TODO, todo_id)
}).catch((error) => {
console.log(error)
})
},
async createTodo({commit}, todoData) {
await Todos.create(todoData)
.then(todo => {
commit(CREATE_TODO, todo)
}).catch((error) => {
console.log(error)
})
},
}
In your project/src/main.js
import Vue from 'vue'
import store from './store'
import App from './App.vue'
import Axios from 'axios'
Vue.prototype.$http = Axios;
new Vue({
store,
render: h => h(App),
}).$mount('#app')
In your project/src/App.vue
import {mapActions, mapGetters} from "vuex";
export default {
name: 'App',
components: {},
data() {
return {}
},
methods: {
...mapActions(['setTodos','patchTodo','createTodo','deleteTodo']),
},
computed: {
...mapGetters(['getTodos']),
},
async mounted() {
await this.setTodos()
},
}
I simply used this in my vue app, and everything worked smoothly.
axios.defaults.xsrfCookieName = 'csrftoken';
axios.defaults.xsrfHeaderName = 'X-CSRFToken';
axios({
method: 'post',
url: 'http://127.0.0.1:8000/api/orders-update',
xstfCookieName: 'csrftoken',
xsrfHeaderName: 'X-CSRFToken',
data: updateIDs,
headers: {
'X-CSRFToken': 'csrftoken',
}
}).then(response => console.log(response));
Site-Wide URL:
from user import urls as user_urls
app_name='user'
urlpatterns = [
re_path(r'^user/',include(user_urls)),
]
Since the admin app, also defines URL patterns named login and logout in django/contrib/admin/sites.py. I need Django pointing to user app.
It's still pointing towards registration/login.html (i.e admin app). I tried namespacing but its been removed in Django 2.0.
user/urls.py :
urlpatterns = [
path(r'',RedirectView.as_view()),
re_path(
r'^login/$',auth_views.LoginView.as_view(template_name='user/login.html'),
name='login'
),
re_path(
r'^logout/$',auth_views.LogoutView.as_view(template_name='user/logged_out.html')
,
{
'extra_context':{'form':AuthenticationForm }
}, name='logout'
),
]
In order to access the URLs by namespace in django 2 you need to move you app_name attribute so user/urls.py would become;
app_name = 'user'
urlpatterns = [
path(r'', RedirectView.as_view()),
re_path(
r'^login/$',auth_views.LoginView.as_view(),
{'template_name':'user/login.html'},
name='login'
),
re_path(
r'^logout/$',auth_views.LogoutView.as_view(),
{
'template_name':'user/logged_out.html',
'extra_context':{'form':AuthenticationForm }
},
name='logout'
),
]
The URLs defined in users.urls will have an application namespace of user.
Alternatively you could namespace URLs in the same file by doing;
user_patterns = ([
path(r'', RedirectView.as_view()),
re_path(
r'^login/$',auth_views.LoginView.as_view(),
{'template_name':'user/login.html'},
name='login'
),
re_path(
r'^logout/$',auth_views.LogoutView.as_view(),
{
'template_name':'user/logged_out.html',
'extra_context':{'form':AuthenticationForm }
},
name='logout'
),
], 'user')
urlpatterns = [
re_path(r'^user/', include(user_patterns)),
]
The docs on this can be found here; https://docs.djangoproject.com/en/2.0/topics/http/urls/#url-namespaces-and-included-urlconfs
I am trying to read json file data to my Html page, but getting 'No provider for ConnectionBackend!
See below code
Home.ts
import { Component } from '#angular/core';
import { NavController ,Platform} from 'ionic-angular';
import { SampleDataService } from '../../providers/sample-data-service';
#Component({
selector: 'page-home',
templateUrl: 'home.html'
})
export class HomePage {
myjsondata:any;
constructor(public navCtrl: NavController, platform: Platform,
sampleDataService:SampleDataService) {
sampleDataService.getJsonData().subscribe((data) => {
console.log("what is in the data ", data);
this.myjsondata = data;
});
}
ngOnInit(){}
}
app.component.ts
import { SampleDataService } from '../providers/sample-data-service';
import { Http } from '#angular/http';
#Component({
templateUrl: 'app.html',
providers:[SampleDataService,Http]
})
export class MyApp {
#ViewChild(Nav) nav: Nav;
rootPage: any = HomePage;
pages: Array<{title: string, component: any}>;
constructor(public platform: Platform, public statusBar: StatusBar,
public splashScreen: SplashScreen, sampleDataService:SampleDataService,
http:Http) {
statusBar.styleDefault();
sampleDataService.getJsonData();
this.initializeApp();
app.module.ts
import { SampleDataService } from '../providers/sample-data-service';
import { Http} from '#angular/http';
#NgModule({
declarations: [
MyApp,
HomePage,
ListPage,
About,
Contact,
AboutCity
],
imports: [
BrowserModule,
IonicModule.forRoot(MyApp)
//AutoCompleteModule,
],
bootstrap: [IonicApp],
entryComponents: [
MyApp,
HomePage,
ListPage,
About,
Contact,
AboutCity
],
providers: [
StatusBar,
SplashScreen,
{provide: ErrorHandler, useClass: IonicErrorHandler},
SampleDataService,
Http
]
})
I tried a lot but not getting solution why this error is.
Can please anyone help me.
You have to import HttpModule in the imports section in the app.module.ts
Also, remove the Http from the providers.
import { SampleDataService } from '../providers/sample-data-service';
import { HttpModule} from '#angular/http';
#NgModule({
declarations: [
MyApp,
HomePage,
ListPage,
About,
Contact,
AboutCity
],
imports: [
BrowserModule,
HttpModule,
IonicModule.forRoot(MyApp)
//AutoCompleteModule,
],
bootstrap: [IonicApp],
entryComponents: [
MyApp,
HomePage,
ListPage,
About,
Contact,
AboutCity
],
providers: [
StatusBar,
SplashScreen,
{provide: ErrorHandler, useClass: IonicErrorHandler},
SampleDataService,
]
})
Please see this highly voted answer as well.
I am new to ionic 2,by following this tutorial https://www.joshmorony.com/creating-a-custom-expandable-header-component-for-ionic-2/ i wanted to display the Expandable header component. Here i created the custom component naming ionic g component ExpandableHeader when i import it in app.module.ts.
Below is my app.module.ts code:
import { ExpandableHeader } from '../components/expandable-
header/expandable-header';
import { NgModule, ErrorHandler } from '#angular/core';
import { IonicApp, IonicModule, IonicErrorHandler } from 'ionic-angular';
import { MyApp } from './app.component';
import { HomePage } from '../pages/home/home';
import { StatusBar } from '#ionic-native/status-bar';
import { SplashScreen } from '#ionic-native/splash-screen';
#NgModule({
declarations: [
MyApp,
HomePage,
ExpandableHeader
],
imports: [
IonicModule.forRoot(MyApp)
],
bootstrap: [IonicApp],
entryComponents: [
MyApp,
HomePage
],
providers: [
StatusBar,
SplashScreen,
{provide: ErrorHandler, useClass: IonicErrorHandler}
]
})
export class AppModule {}
When i try to import it shows the error.How can i solve this error
Try this providers: [StatusBar,SplashScreen,ErrorHandler]
and Try to define provide: and useClass in your page constructor.
I am trying to show tabs on android but not shown
it is shown on web page
Where is the problem
My code is ->
html part:
<ion-tabs>
<ion-tab tabIcon="water" tabTitle="Water" [root]="Tabroot1"></ion-tab>
<ion-tab tabIcon="leaf" tabTitle="Life" [root]="Tabroot2"></ion-tab>
<ion-tab tabIcon="flame" tabTitle="Fire" [root]="Tabroot3"></ion-tab>
<ion-tab tabIcon="magnet" tabTitle="Force" [root]="Tabroot4"></ion-tab>
</ion-tabs>
typscript part
import {Component} from '#angular/core';
import {NavController} from 'ionic-angular';
import {IsimPage} from '../game/isim/isim';
import {SehirPage} from '../game/sehir/sehir';
import {HayvanPage} from '../game/hayvan/hayvan';
import {BitkiPage} from '../game/bitki/bitki';
#Component({
selector:'page-yeniOyun',
templateUrl:'yeniOyun.html'
})
export class YeniOyunPage{
Tabroot1: any
Tabroot2: any
Tabroot3: any
Tabroot4: any
constructor(public naVCtrl: NavController){
this.Tabroot1 = IsimPage;
this.Tabroot2 = SehirPage;
this.Tabroot3 = HayvanPage;
this.Tabroot4 = BitkiPage;
}
}
Thank you 'Dag'.I solved problem in differen way and solve is about my ionic html structure.
Typescipt part and html part true,wrong is my tabs page
html part:
<ion-tabs>
<ion-tab tabIcon="water" tabTitle="Water" [root]="Tabroot1"></ion-tab>
<ion-tab tabIcon="leaf" tabTitle="Life" [root]="Tabroot2"></ion-tab>
<ion-tab tabIcon="flame" tabTitle="Fire" [root]="Tabroot3"></ion-tab>
<ion-tab tabIcon="magnet" tabTitle="Force" [root]="Tabroot4"></ion-tab>
typescript part
import {Component} from '#angular/core';
import {NavController} from 'ionic-angular';
import {IsimPage} from '../game/isim/isim';
import {SehirPage} from '../game/sehir/sehir';
import {HayvanPage} from '../game/hayvan/hayvan';
import {BitkiPage} from '../game/bitki/bitki';
#Component({
selector:'page-yeniOyun',
templateUrl:'yeniOyun.html'
})
export class YeniOyunPage{
Tabroot1: any
Tabroot2: any
Tabroot3: any
Tabroot4: any
constructor(public naVCtrl: NavController){
this.Tabroot1 = IsimPage;
this.Tabroot2 = SehirPage;
this.Tabroot3 = HayvanPage;
this.Tabroot4 = BitkiPage;
}
}
IsimPage:
<ion-header>
<ion-navbar>
<ion-title>
IsimPage
</ion-title>
</ion-navbar>
</ion-header>
<ion-content padding>
//Mytab interface here
</ion-content>
SehirPage:
<ion-header>
<ion-navbar>
<ion-title>
SehirPage
</ion-title>
</ion-navbar>
</ion-header>
<ion-content padding>
//Mytab interface here
</ion-content>
HayvanPage:
<ion-header>
<ion-navbar>
<ion-title>
HayvanPage
</ion-title>
</ion-navbar>
</ion-header>
<ion-content padding>
//Mytab interface here
</ion-content>
BitkiPage:
<ion-header>
<ion-navbar>
<ion-title>
BitkiPge
</ion-title>
</ion-navbar>
</ion-header>
<ion-content padding>
//Mytab interface here
</ion-content>