Reputation: 5
I have been developing a pretty basic site, I have used tons of GPT but one issue both me and GPT have been unable to figure out is how after login, the site is not able to redirect. I am trying to redirect it to another page after a successful login. A JWT token is being generated but something I have not been able to figure out.
from flask import Flask, request, jsonify, render_template
from flask_sqlalchemy import SQLAlchemy
from flask_bcrypt import Bcrypt
from flask_jwt_extended import JWTManager, create_access_token, jwt_required, get_jwt_identity
from flask_cors import CORS
from flask_jwt_extended import verify_jwt_in_request, get_jwt_identity
import os
# Flask app configuration
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://root:#######@127.0.0.1/stockroom_db'
app.config['JWT_SECRET_KEY'] = 'your_jwt_secret_key' # Replace with a strong secret key
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False # Disable to save resources
# Initialize extensions
db = SQLAlchemy(app)
bcrypt = Bcrypt(app)
jwt = JWTManager(app)
# User model definition
class User(db.Model):
__tablename__ = 'users'
user_id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(50), unique=True, nullable=False)
email = db.Column(db.String(100), unique=True, nullable=False)
password_hash = db.Column(db.String(255), nullable=False)
created_at = db.Column(db.DateTime, default=db.func.current_timestamp())
def set_password(self, password):
self.password_hash = bcrypt.generate_password_hash(password).decode('utf-8')
def check_password(self, password):
return bcrypt.check_password_hash(self.password_hash, password)
# Signup route for user registration
@app.route('/signup', methods=['POST'])
def signup():
data = request.json
username = data.get('username')
email = data.get('email')
password = data.get('password')
# Check if username or email already exists
if User.query.filter((User.username == username) | (User.email == email)).first():
return jsonify({"error": "Username or Email already exists"}), 400
# Create a new user instance
new_user = User(username=username, email=email)
new_user.set_password(password)
# Save the new user to the database
db.session.add(new_user)
db.session.commit()
return jsonify({"message": "User registered successfully"}), 201
# Login route for user authentication
@app.route('/login', methods=['POST'])
def login():
data = request.json
username = data.get('username')
password = data.get('password')
# Find the user by username
user = User.query.filter_by(username=username).first()
# Check if user exists and password is correct
if user and user.check_password(password):
# Create JWT token
access_token = create_access_token(identity=user.user_id)
return jsonify({"access_token": access_token}), 200
return jsonify({"error": "Invalid username or password"}), 401
@app.before_request
def handle_options_request():
if request.method == "OPTIONS":
return jsonify({"status": "OK"}), 200
@app.route('/myStockroom', methods=['GET'])
@jwt_required() # Enforce JWT validation
def my_stockroom():
try:
# Log the Authorization header
auth_header = request.headers.get('Authorization')
print(f"Authorization Header Received: {auth_header}")
# Extract user ID from JWT
user_id = get_jwt_identity()
print(f"User ID from JWT: {user_id}")
# Fetch user from the database
user = User.query.get(user_id)
if user:
return jsonify({"username": user.username}), 200
else:
return jsonify({"error": "User not found"}), 404
except Exception as e:
print(f"Error in myStockroom route: {e}")
return jsonify({"error": "Unauthorized access"}), 401
CORS(app, resources={r"/*": {"origins": "*"}}, supports_credentials=True, expose_headers=["Authorization"])
# Main entry point for running the application
if __name__ == "__main__":
# Create tables if they don't exist
with app.app_context():
db.create_all()
app.run(host="127.0.0.1", port=5555, debug=True)
The above code is my app.py
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Stockroom - Manage Your Inventory Seamlessly</title>
<link rel="stylesheet" href="\StockRoom\static\style.css">
</head>
<body>
<div class="container">
<div class="logo">
<img src="" alt="Stockroom Logo">
</div>
<div class="tagline">Manage your inventory, seamlessly.</div>
<div class="button-container">
<button class="cta-button" onclick="openModal('signup')">SIGN UP</button>
<button class="cta-button" onclick="openModal('login')">LOGIN</button>
</div>
</div>
<img src="\StockRoom\static\StockRoom Frontend Design_20240914_161105_0000.png" alt="Background Image" class="background-image">
<!-- Signup Modal -->
<div id="signupModal" class="modal">
<div class="modal-content">
<span class="close-button" onclick="closeModal('signup')">×</span>
<h2>Sign Up</h2>
<label class="form-label">Username</label>
<input type="text" class="form-input" id="signupUsername">
<label class="form-label">Email</label>
<input type="email" class="form-input" id="signupEmail">
<label class="form-label">Password</label>
<input type="password" class="form-input" id="signupPassword">
<button class="form-button" onclick="handleSignup()">Sign Up</button>
<p class="message" id="signupMessage"></p>
</div>
</div>
<!-- Login Modal -->
<div id="loginModal" class="modal">
<div class="modal-content">
<span class="close-button" onclick="closeModal('login')">×</span>
<h2>Login</h2>
<label class="form-label">Username</label>
<input type="text" class="form-input" id="loginUsername">
<label class="form-label">Password</label>
<input type="password" class="form-input" id="loginPassword">
<button class="form-button" onclick="handleLogin()">Login</button>
<p class="message" id="loginMessage"></p>
</div>
</div>
<script>
// Open modal function
function openModal(type) {
document.getElementById(type + 'Modal').style.display = 'block';
}
// Close modal function
function closeModal(type) {
document.getElementById(type + 'Modal').style.display = 'none';
}
// Handle signup function
async function handleSignup() {
const username = document.getElementById('signupUsername').value;
const email = document.getElementById('signupEmail').value;
const password = document.getElementById('signupPassword').value;
const signupMessage = document.getElementById('signupMessage');
try {
const response = await fetch('http://127.0.0.1:5555/signup', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ username, email, password })
});
const data = await response.json();
if (response.ok) {
signupMessage.style.color = "green";
signupMessage.innerText = "Signup successful! Please log in.";
closeModal('signup');
} else {
signupMessage.style.color = "red";
signupMessage.innerText = data.error || "Signup failed. Try again.";
console.error("Signup Error:", data); // Log detailed error info
}
} catch (error) {
signupMessage.innerText = "An error occurred. Please try again.";
console.error("Network Error:", error); // Log network error details
}
}
// Handle login function
async function handleLogin() {
const username = document.getElementById('loginUsername').value;
const password = document.getElementById('loginPassword').value;
const loginMessage = document.getElementById('loginMessage');
try {
const response = await fetch('http://127.0.0.1:5555/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ username, password })
});
const data = await response.json();
if (response.ok && data.access_token) {
// Store the JWT token in sessionStorage
sessionStorage.setItem('token', data.access_token);
console.log('Stored Token:', sessionStorage.getItem('token'));
// Update the message to indicate success
loginMessage.style.color = "green";
loginMessage.innerText = "Login successful! Redirecting...";
// Close the modal
closeModal('login');
// Redirect to myStockroom page after a brief delay
setTimeout(() => {
window.location.href = "http://127.0.0.1:5555/myStockroom"; // Use absolute URL
}, 1500);
} else {
// Handle login failure
loginMessage.style.color = "red";
loginMessage.innerText = data.error || "Login failed. Check credentials.";
}
} catch (error) {
// Handle network errors
loginMessage.style.color = "red";
loginMessage.innerText = "An error occurred. Please try again.";
console.error("Network Error:", error); // Log the error for debugging
}
}
// Fetch user data for myStockroom page
window.onload = function () {
const token = sessionStorage.getItem('token'); // Retrieve JWT token
if (!token) {
alert("You are not logged in!");
window.location.href = "/login"; // Redirect if no token
return;
}
fetch('/myStockroom', {
method: 'GET',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${sessionStorage.getItem('token')}`// Add token to Authorization header
}
})
.then(response => {
if (response.status === 401) {
// Handle unauthorized access
alert("Session expired. Please log in again.");
sessionStorage.removeItem('token'); // Clear invalid token
window.location.href = "/login";
} else {
return response.json();
}
})
.then(data => {
if (data.username) {
document.getElementById('username').textContent = data.username; // Update username
} else {
console.error("Error: Username not found.");
}
})
.catch(error => {
console.error('Error:', error);
alert("An error occurred while fetching user data.");
});
};
// Close modals if clicked outside
window.onclick = function (event) {
const signupModal = document.getElementById('signupModal');
const loginModal = document.getElementById('loginModal');
if (event.target === signupModal) signupModal.style.display = 'none';
if (event.target === loginModal) loginModal.style.display = 'none';
};
</script>
</body>
</html>
the above code is my login page
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>My Stockroom Inventory</title>
<link rel="stylesheet" href="\StockRoom\static\style.css">
</head>
<body>
<div class="sidebar">
<img src="\StockRoom\static\stockroom White.png" alt="Stockroom Logo">
<p class="highlight">my stockroom</p>
<p>inventory</p>
<p>new order</p>
<div class="bottom-links">
<p>account</p>
<p>homepage</p>
<p>help</p>
</div>
</div>
<div class="banner">
<h1>My Stockroom</h1>
</div>
<div class="main-content">
<h1>Welcome, <span id="username"></span>!</h1>
<div class="form-container">
<div>
<label class="input-label">DATE:</label>
<input type="text"/>
</div>
<div>
<label class="input-label">ORDER#:</label>
<input type="text"/>
</div>
<div>
<label class="input-label">CUSTOMERNAME:</label>
<input type="text"/>
</div>
<div>
<label class="input-label">TOTAL ORDER VALUE (TOV):</label>
<input type="text"/>
</div>
</div>
</div>
<!-- Add this JavaScript at the end of the body section -->
<script>
// Fetch user data using JWT token
window.onload = function() {
const token = sessionStorage.getItem('token'); // Retrieve the JWT token from sessionStorage
// Check if the token exists
if (!token) {
alert("You are not logged in!");
window.location.href = "/login"; // Redirect to login page if not logged in
return;
}
// Make a fetch request to the /myStockroom endpoint to get user data
fetch('/myStockroom', {
method: 'GET',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}` // Add Authorization header
}
})
.then(response => response.json())
.then(data => {
// Use data to update the UI (for example, show username or other info)
if (data.username) {
document.getElementById('username').textContent = data.username; // Update username dynamically
} else {
console.error("Error: Username not found in response.");
}
})
.catch(error => {
console.error('Error:', error);
alert("An error occurred while fetching user data.");
});
};
</script>
</body>
</html>
This code is the page it should redirect to, please help me figure this redirection
Upvotes: 0
Views: 54
Reputation: 28
What is the error you encounter?
I guess that this is this part:
// Redirect to myStockroom page after a brief delay
setTimeout(() => {
window.location.href = "http://127.0.0.1:5555/myStockroom"; // Use absolute URL
}, 1500);
and your server answers that it is not possible to GET
there because of @jwt_required
?
If this is the case, this can be explained because the browser will not add the Authorization:
header to the GET
. Hence first you login, then you are redirected to /myStockroom
but this request is refused by the server because it requires a JWT.
Please post console log from the browser and from the flask output to confirm this.
If this is the problem, you could add the JWT token in a cookie when /login
and tell that to the decorator @jwt_required(locations='cookies')
. The cookie name seems configurable with JWT_ACCESS_COOKIE_NAME
and defaults to access_token_cookie
.
By the way, you should also change your password which is in clear text in the URL to connect to your DB (and can be seen in the history of edits of your messages)...
Upvotes: 0