I'm trying to add authentication to my django-react app. At this point I am able to login/register users and it works fine but I want to get only data which is related with user logged in so posted or updated by them. Now I get all data regardless of user which is authenticated.
I assume I have to change it in my views but how to do this?
This is one of my classes
class ListView(viewsets.ModelViewSet):
serializer_class = ListSerializer
queryset = List.objects.all()
And on frontend side I get data this way:
const getList = async () => {
try {
const response = await axiosInstance.get('/list/')
if(response){
setList(response.data)
}
}catch(error){
throw error;
}
}
You can use Django Rest Framework to set the authentication scheme on a per-view or per-viewset basis. Using the APIView class-based views:
from rest_framework.authentication import SessionAuthentication, BasicAuthentication
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.views import APIView
class ExampleView(APIView):
authentication_classes = [SessionAuthentication, BasicAuthentication]
permission_classes = [IsAuthenticated]
def get(self, request, format=None):
content = {
'user': str(request.user), # `django.contrib.auth.User` instance.
'auth': str(request.auth), # None
}
return Response(content)
Remember to set it up:
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.BasicAuthentication',
'rest_framework.authentication.SessionAuthentication',
]
}
Read more here
Related
My code currently consists of a frontend in react and a flask backend api. I'm trying to establish a session in my backend using flask sessions, but I'm unable to, since flask never makes contact with the user, and all requests go through the frontend. To that end, I'm trying to post cookies to
In the frontend, I have something like
import Cookies from 'universal-cookie';
class thingy extends React.Component{
constructor(props) {
this.backendurl = 'localhost:5000'
const cookies = new Cookies();
this.username = this.props.match.params.user
cookies.set('UserName', ''+JSON.stringify(this.username), { path:
'/profile' });
}
onclick = ()=>{
#post something using axios that sends the cookie to the flask backend so it can be processed
}
}
render(){
return(
<button onClick = {this.onclick}>Click Here</button>
)
}
}
backend:
app = Flask(__name__)
app.config["SESSION_PERMANENT"] = False
Session(app)
#app.route('/user',methods=['POST'])
def info():
#do something with the cookie that react posted in order to user flask_session
return user.name
Does someone know how to send the cookies from react to flask, and then input the cookies recieved by flask into the flask session?
I have a project using React (frontend) and Django Rest Framework (backend), and it is currently deployed on PythonAnywhere. I'm using axios to connect to my API and load data from my database onto the React frontend.
During development, I hardcoded the username and password for accessing the database into my index.js file (credentials are obscured below):
import React from 'react';
import ReactDOM from 'react-dom';
import App from './components/App.js';
import axios from 'axios';
import 'semantic-ui-css/semantic.min.css';
import 'lightgallery.js/dist/css/lightgallery.css';
import './styles.css';
import * as serviceWorker from './serviceWorker';
axios.defaults.xsrfHeaderName = "X-CSRFTOKEN";
axios.defaults.xsrfCookieName = "csrftoken";
axios.defaults.withCredentials = true;
axios.post('/login/', { username: [HARD_CODED_USERNAME], password: [HARD_CODED_PASSWORD] }).then(rv => {
console.log('Login', rv)
}).catch(err => {
console.log('Login error', err.response)
});
const updatePhoto = () => {
axios.patch('https://[WEBSITEADDRESS.COM]/api/photos/').then(resp => {
console.log('Update response', resp)
}).catch(error => {
console.log("Update error", error)
})
}
ReactDOM.render(
<App />,
document.getElementById('root')
);
serviceWorker.unregister();
This works, however the username and password are viewable upon inspection in the browser. Not only that, but the Django admin as well as the API is accessible to anyone, because it automatically logs them in using my username and password!
I then tried using an .env file located at the root of my create-react-app project (same level with my package.json file):
REACT_APP_USERNAME=myusername
REACT_APP_PASSWORD=mypassword
And I updated my index.js file to as follows:
const my_user_name = process.env.REACT_APP_USERNAME;
const my_password = process.env.REACT_APP_PASSWORD;
axios.post('/login/', { username: my_user_name, password: my_password }).then(rv => {
console.log('Login', rv)
}).catch(err => {
console.log('Login error', err.response)
});
However, this still does not obscure the credentials from inspection in the browser, and, while it does solve the issue of automatically logging anyone into my Django admin and API, the data from the database is not shown on the website.
My questions are as follows:
How do I properly set up axios to access my API and display data on my website WITHOUT logging someone into my Django admin?
How do I properly set up environment variables in React to hide sensitive data when using the browser's inspection tools?
Any help is much appreciated!
UPDATE: SOLUTION
Based on #Lior_Pollak's comment on his answer below, I managed to solve both of my issues by creating a public, read-only API endpoint on the backend. Anyone can view the API but cannot post, update, or delete data, nor can they access the Django admin. And no sensitive data is displayed in the browser's inspection tool, yet all my photos are displayed on the website. :)
In case anyone else stumbles across this question, I've provided the code I've used successfully below (both backend and frontend):
Frontend: index.js
import React from 'react';
import ReactDOM from 'react-dom';
import App from './components/App.js';
import 'semantic-ui-css/semantic.min.css';
import 'lightgallery.js/dist/css/lightgallery.css';
import './styles.css';
import * as serviceWorker from './serviceWorker';
/*Removed all code related to axios; was not needed here*/
ReactDOM.render(
<App />,
document.getElementById('root')
);
serviceWorker.unregister();
Backend: views.py
from django.views.generic import View
from django.http import HttpResponse
from django.conf import settings
from rest_framework import generics
from rest_framework import permissions
from .models import Photo
from .serializers import PhotoSerializer
import logging
import os
class PhotoList(generics.ListCreateAPIView):
permission_classes = [permissions.IsAuthenticatedOrReadOnly]
queryset = Photo.objects.filter(show=True).order_by('order')
serializer_class = PhotoSerializer
class FrontendAppView(View):
def get(self, request):
print (os.path.join(settings.REACT_APP_DIR, 'build', 'index.html'))
try:
with open(os.path.join(settings.REACT_APP_DIR, 'build', 'index.html')) as f:
return HttpResponse(f.read())
except FileNotFoundError:
logging.exception('Production build of app not found')
return HttpResponse(status=501)
Backend: urls.py
from django.conf.urls import include, url
from rest_framework import routers
from backend import views
router = routers.DefaultRouter()
urlpatterns = [
url(r'^api/', include(router.urls)),
url(r'^api/photos/$', views.PhotoList.as_view()),
]
You are trying to obscure client data, which (for obvious reasons) resides in the client.
So you can't really obscure it.
You can force the user to login with their credentials, which is how authentication using username and password is done.
I am trying to setup the paymentIntent API from Stripe but I can't seem to figure out the error I am getting. I followed along from this video: https://www.youtube.com/watch?v=w1oLdAPyuok&t=1414s
I have a react frontend which makes a request to my Django view:
try {
const { data: clientSecret } = await axios.post("http://127.0.0.1:8000/paymentIntent/", {
amount: price * 100
});
My view:
from django.shortcuts import render
from django.http import HttpResponse
from django.views.generic import View
from django.views.decorators.csrf import csrf_exempt
import logging
from rest_framework.views import APIView
from rest_framework import status, generics
from rest_framework.response import Response
from rest_framework.decorators import api_view
from django.conf import settings
import stripe
stripe.api_key = "pk_test_51HWMwZB5hTmoPZOBJd00GjCvDYUg"
#api_view(['POST'])
def payment(request):
try:
amount = request.body
paymentIntent = stripe.PaymentIntent.create(
amount = amount,
currency = "usd",
# payment_method_types=['card'],
# capture_method='manual',
metadata={'integration_check': 'accept_a_payment'},
)
data = paymentIntent.client_secret
return Response(data,status=status.HTTP_200_OK)
except :
return Response(status=status.HTTP_400_BAD_REQUEST)
When I make the request it just says 400 Bad Request with no response data
I don't see the actual error message you're getting, your server should log out the error in your try-catch block, as shown here: https://stripe.com/docs/api/errors/handling?lang=python allowing you to better debug and troubleshoot as you build your integration.
Most likely, it is that you have set your publishable key as your stripe-python API key. Instead you need to initialize stripe with your secret key: https://stripe.com/docs/api/authentication?lang=python
I have little/no knowdlege in AngularJs, i want to create a very simple SPA with django as backend and AngularJs as frontend. User will be able to Register, Login & logout all taking place on the same page when a user logs in they will see a message"Welcome (user email)".
This is very easy to do in a normal django web app as we don't even need to create the whole authentication system. But i want to learn how to do this with AngularJS as my employer wants me to do.
I have read the basics of AngularJs and it looked well explained (it made sense) but how to integrate it with django. I tried searching on the internet but there is nothing out there, the tutorials that are there are more then 7 years old.
First you need to look at angular HttpClient because that what going to enable communication between django and angular..then create a service to handle authentication you can call it anything import HttpClient inside to login user for example i will do this:
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
import { Observable } from 'rxjs';
import { environment } from 'src/environments/environment';
import { Router } from '#angular/router';
#Injectable({
providedIn: 'root'
})
export class AuthServiceService {
constructor(private http: HttpClient, private router: Router) { }
// Skip authorization from these requests
private skip_token_headers = {
skip: "true"
};
loginUser(user): Observable<any> {
return this.makePostRequest(environment.LOGIN_URL, user,
this.skip_token_headers);
}
makePostRequest(url: string, data: any, req_headers: any): Observable<any> {
return this.http.post(url, data, { headers: req_headers });
}
then in your login component under .ts you import your service and use it like bellow
onLoginSuccess(result){
localStorage.setItem('token', result.key);
localStorage.setItem('user', JSON.stringify(result.user));
this.router.navigate(['/userpage']);
}
onSubmit(form: NgForm) {
this.authService.loginUser(this.user).subscribe(
result => {
this.onLoginSuccess(result);
},
error => {
this.login_errors = [];
if (error['error']['non_field_errors']) {
this.login_errors = error['error']['non_field_errors'];
}
// this.clearErrors(this.user);
// this.showErrors(error);
}
);
}
I am learning about Next.JS and React and was wondering if it is possible to get user details from the cookie storing the JWT.
I have managed to set the JWT as the cookie and can log it successfully and have also managed to decode it but can't find anything on how to get username, id, etc from it. Here's what I have so far:
import React from "react";
import App from "../components/App.js";
import cookie from "react-cookies";
import jwt_decode from "jwt-decode";
export default class Dashboard extends React.Component {
static async getInitialProps() {
const token = cookie.load("jwt");
return { token };
}
constructor(props) {
super(props);
this.state = props.token;
}
render() {
const current_user = jwt_decode(this.props.token, { header: true });
return (
<App>
<p>Username: {current_user.username}</p>
</App>
);
}
}
Ideally, i'd like to be able to set the cookie value to a user variable and extract properties from it, e.g. current_user.username. Unless i've got it completely wrong and have missed out something really important! Any help would be massively appreciated!
You can use this parseJwt function to extract the user data:
function parseJwt(token) {
if (!token) { return; }
const base64Url = token.split('.')[1];
const base64 = base64Url.replace('-', '+').replace('_', '/');
return JSON.parse(window.atob(base64));
}
console.log(parseJwt('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c'))
It will extract the data inside a jwt token and will return an object
You can use npm package. Simply run npm install jwt-decode in the cmd and use the following code:
import jwt_decode from "jwt-decode";
const token = "eyJ0eXAiO.../// jwt token";
const decoded = jwt_decode(token);