Under UserAPI there are nested classes Security and CRUD.
CRUD is an acronym related to the basic operations done on data within a database
Create: POST requests
Creates new user with input data
Performs error checking
Sets up user object -> adds to user database
Read: GET requests
Handles user retrieval requests
Data -> JSON + response
Update: PUT/PATCH requests
Updates based on user input
Commits changes to user database
This is done with the PUT request
Delete: DELETE requests
Handles user delete requests
Deletes user from database
Validates data through HTTP POST requests
Find user id and checks validity of entered password with that stored
JSON response with authentication status, ex. Login if valid, and no login in invalid
Not necessarily authorization - authentication allows login while authorization allows access to a certain resource
Create request used for the addition of new users
Post-request displays are user data table
Put request implemented to update user information
Delete request removes specified users
// uri variable and options object are obtained from config.js
import { uri, options } from '/sharonk/assets/js/api/config.js';
const url = uri + '/api/users/authenticate';
const body = {
// name: document.getElementById("name").value,
uid: "toby",
password: "123toby"
// dob: document.getElementById("dob").value
};
const authOptions = {
...options, // This will copy all properties from options
method: 'POST', // Override the method property
cache: 'no-cache', // Set the cache property
body: JSON.stringify(body)
};
fetch(url, authOptions)
function login_user(){
// Set Authenticate endpoint
const url = uri + '/api/users/';
// Set the body of the request to include login data from the DOM
const body = {
name: document.getElementById("name").value,
uid: document.getElementById("uid").value,
password: document.getElementById("password").value,
dob: document.getElementById("dob").value
};
// Change options according to Authentication requirements
const authOptions = {
...options, // This will copy all properties from options
method: 'POST', // Override the method property
cache: 'no-cache', // Set the cache property
body: JSON.stringify(body)
};
// Fetch JWT
fetch(url, authOptions)
.then(response => {
// handle error response from Web API
if (!response.ok) {
const errorMsg = 'Login error: ' + response.status;
console.log(errorMsg);
return;
}
// Success!!!
// Redirect to the database page
window.location.href = "/sharonk/data/database";
})
// catch fetch errors (ie ACCESS to server blocked)
.catch(err => {
console.error(err);
});
}
// Attach login_user to the window object, allowing access to form action
window.login_user = login_user;
@token_required
def post(self, current_user): # Create method
''' Read data for json body '''
body = request.get_json()
''' Avoid garbage in, error checking '''
# validate name
name = body.get('name')
if name is None or len(name) < 2:
return {'message': f'Name is missing, or is less than 2 characters'}, 400
# validate uid
uid = body.get('uid')
if uid is None or len(uid) < 2:
return {'message': f'User ID is missing, or is less than 2 characters'}, 400
# look for password and dob
password = body.get('password')
dob = body.get('dob')
''' #1: Key code block, setup USER OBJECT '''
uo = User(name=name,
uid=uid)
''' Additional garbage error checking '''
# set password if provided
if password is not None:
uo.set_password(password)
# convert to date type
if dob is not None:
try:
uo.dob = datetime.strptime(dob, '%Y-%m-%d').date()
except:
return {'message': f'Date of birth format error {dob}, must be mm-dd-yyyy'}, 400
# This is code from the user.py in the model
def create(self):
try:
# creates a person object from User(db.Model) class, passes initializers
db.session.add(self) # add prepares to persist person object to Users table
db.session.commit() # SqlAlchemy "unit of work pattern" requires a manual commit
return self
except IntegrityError:
db.session.remove()
return None
// uri variable and options object are obtained from config.js
import { uri, options } from '/sharonk/assets/js/api/config.js';
function login_user(){
// Set Authenticate endpoint
const url = uri + '/api/users/authenticate';
// Set the body of the request to include login data from the DOM
const body = {
name: document.getElementById("name").value,
uid: document.getElementById("uid").value,
password: document.getElementById("password").value,
dob: document.getElementById("dob").value
};
// Change options according to Authentication requirements
const authOptions = {
...options, // This will copy all properties from options
method: 'POST', // Override the method property
cache: 'no-cache', // Set the cache property
body: JSON.stringify(body)
};
// Fetch JWT
fetch(url, authOptions)
.then(response => {
// handle error response from Web API
if (!response.ok) {
const errorMsg = 'Login error: ' + response.status;
console.log(errorMsg);
return;
}
// Success!!!
// Redirect to the database page
window.location.href = "/sharonk/data/database";
})
// catch fetch errors (ie ACCESS to server blocked)
.catch(err => {
console.error(err);
});
}
def post(self):
try:
body = request.get_json()
if not body:
return {
"message": "Please provide user details",
"data": None,
"error": "Bad request"
}, 400
''' Get Data '''
uid = body.get('uid')
if uid is None:
return {'message': f'User ID is missing'}, 400
password = body.get('password')
''' Find user '''
user = User.query.filter_by(_uid=uid).first()
if user is None or not user.is_password(password):
return {'message': f"Invalid user id or password"}, 400
if user:
try:
token = jwt.encode(
{"_uid": user._uid},
current_app.config["SECRET_KEY"],
algorithm="HS256"
)
resp = Response("Authentication for %s successful" % (user._uid))
resp.set_cookie("jwt", token,
max_age=3600,
secure=True,
httponly=True,
path='/',
samesite='None' # This is the key part for cross-site requests
# domain="frontend.com"
)
return resp
fetch(url, authOptions)
function login_user(){
// Set Authenticate endpoint
const url = uri + '/api/users/';
// Set the body of the request to include login data from the DOM
const body = {
uid: document.getElementById("uid").value,
dob: document.getElementById("dob").value,
favfood: document.getElementById("favfood").value
};
// Change options according to Authentication requirements
const authOptions = {
...options, // This will copy all properties from options
method: 'PUT', // Override the method property
cache: 'no-cache', // Set the cache property
body: JSON.stringify(body)
};
// Fetch JWT
fetch(url, authOptions)
.then(response => {
// handle error response from Web API
if (!response.ok) {
const errorMsg = 'Login error: ' + response.status;
console.log(errorMsg);
return;
}
// Success!!!
// Redirect to the database page
window.location.href = "/sharonk/data/database";
})
// catch fetch errors (ie ACCESS to server blocked)
.catch(err => {
console.error(err);
});
}
// Attach login_user to the window object, allowing access to form action
window.login_user = login_user;
@token_required
def put(self, current_user):
body = request.get_json() # get the body of the request
uid = body.get('uid') # get the UID (Know what to reference)
dob = body.get('dob')
if dob is not None:
try:
fdob = datetime.strptime(dob, '%Y-%m-%d').date()
except:
return {'message': f'Date of birth format error {dob}, must be mm-dd-yyyy'}, 400
users = User.query.all()
for user in users:
if user.uid == uid:
user.update('','','',fdob)
return f"{user.read()} Updated"
const authOptions = {
...options, // This will copy all properties from options
cache: 'no-cache',
method: 'DELETE',
mode: 'cors',
headers: {
'Content-Type': 'application/json',
// 'Access-Control-Allow-Origin': '*'
},
};
// Fetch JWT
fetch(url, authOptions)
.then(response => {
// handle error response from Web API
if (!response.ok) {
const errorMsg = 'Login error: ' + response.status;
console.log(errorMsg);
return;
}
def delete(self, current_user):
body = request.get_json()
uid = body.get('uid')
users = User.query.all()
for user in users:
if user.uid == uid:
user.delete()
return jsonify(users.read())