Set Up the Environment
First, let’s install the necessary Python libraries:
bashCopy codepip install flask flask-sqlalchemy flask-login flask-wtf cryptography
- Flask: Web framework.
- Flask-SQLAlchemy: ORM for interacting with the SQLite database.
- Flask-Login: For session-based user authentication.
- Flask-WTF: For form handling and CSRF protection.
- Cryptography: For encrypting sensitive user data.
Step 2: Design the Database
We’ll design a simple database that stores:
- User Information (e.g., name, email).
- User Consent for data collection and processing.
- Audit Logs to track actions taken on the data.
models.py
– SQLAlchemy Models
pythonCopy codefrom flask_sqlalchemy import SQLAlchemy
from datetime import datetime
db = SQLAlchemy()
# User Model (store personal info)
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(100), nullable=False)
email = db.Column(db.String(100), unique=True, nullable=False)
password_hash = db.Column(db.String(128), nullable=False)
consent_given = db.Column(db.Boolean, default=False)
consent_date = db.Column(db.DateTime)
encrypted_data = db.Column(db.LargeBinary)
def __repr__(self):
return f"<User {self.name}, Email: {self.email}>"
# Audit Log Model (track user actions)
class AuditLog(db.Model):
id = db.Column(db.Integer, primary_key=True)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
action = db.Column(db.String(200), nullable=False)
timestamp = db.Column(db.DateTime, default=datetime.utcnow)
user = db.relationship('User', backref=db.backref('audit_logs', lazy=True))
def __repr__(self):
return f"<AuditLog {self.action} at {self.timestamp}>"
Explanation:
- User: Stores personal data, consent information, and encrypted data.
- AuditLog: Keeps track of actions performed on user data (such as access, modification, deletion).
Step 3: Implement User Consent Management (GDPR Compliance)
Users must explicitly consent to having their data collected and processed. We’ll include this as part of the registration form.
forms.py
– User Registration Form
pythonCopy codefrom flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, BooleanField, SubmitField
from wtforms.validators import DataRequired, Email
class RegistrationForm(FlaskForm):
name = StringField('Name', validators=[DataRequired()])
email = StringField('Email', validators=[DataRequired(), Email()])
password = PasswordField('Password', validators=[DataRequired()])
consent = BooleanField('I consent to having my data collected and processed', validators=[DataRequired()])
submit = SubmitField('Register')
app.py
– Flask Routes and Logic for Registration and Consent
pythonCopy codefrom flask import Flask, render_template, request, redirect, url_for, flash
from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager, UserMixin, login_user, login_required, logout_user, current_user
from cryptography.fernet import Fernet
from datetime import datetime
from forms import RegistrationForm
# Initialize Flask app
app = Flask(__name__)
app.config['SECRET_KEY'] = 'mysecret'
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///users.db'
db = SQLAlchemy(app)
login_manager = LoginManager(app)
# Load user
@login_manager.user_loader
def load_user(user_id):
return User.query.get(int(user_id))
# User model (already defined above)
class User(UserMixin, db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(100), nullable=False)
email = db.Column(db.String(100), unique=True, nullable=False)
password_hash = db.Column(db.String(128), nullable=False)
consent_given = db.Column(db.Boolean, default=False)
consent_date = db.Column(db.DateTime)
encrypted_data = db.Column(db.LargeBinary)
def __repr__(self):
return f"<User {self.name}, Email: {self.email}>"
# Registration route
@app.route('/register', methods=['GET', 'POST'])
def register():
form = RegistrationForm()
if form.validate_on_submit():
# Check if user consented
if form.consent.data:
# Encrypt sensitive data
key = Fernet.generate_key()
cipher_suite = Fernet(key)
encrypted_data = cipher_suite.encrypt(b"Sensitive User Data")
# Create user
new_user = User(
name=form.name.data,
email=form.email.data,
password_hash=form.password.data,
consent_given=True,
consent_date=datetime.utcnow(),
encrypted_data=encrypted_data
)
db.session.add(new_user)
db.session.commit()
flash("Registration successful", "success")
login_user(new_user)
return redirect(url_for('dashboard'))
else:
flash("You must consent to data collection", "warning")
return render_template('register.html', form=form)
# User Dashboard
@app.route('/dashboard')
@login_required
def dashboard():
return render_template('dashboard.html', name=current_user.name)
# Run the application
if __name__ == '__main__':
app.run(debug=True)
Explanation:
- User Consent: The registration form includes a checkbox (
consent
) that must be checked for the user to consent to data collection. - Encryption: Sensitive data is encrypted using
Fernet
from the cryptography library. You can later implement decryption logic when necessary. - Audit Log: The app doesn’t yet include logging actions to the database, but you could implement that in a similar fashion as shown in the audit log model.
Step 4: Data Access and Deletion API
GDPR and CCPA allow users to access their data and request its deletion. Let’s create the endpoints for these actions.
Data Access and Deletion
pythonCopy codefrom flask import jsonify
@app.route('/access_data', methods=['GET'])
@login_required
def access_data():
# Decrypt the user data
cipher_suite = Fernet(b"Your_Encryption_Key")
decrypted_data = cipher_suite.decrypt(current_user.encrypted_data).decode()
return jsonify({
"name": current_user.name,
"email": current_user.email,
"decrypted_data": decrypted_data,
"consent_given": current_user.consent_given,
"consent_date": current_user.consent_date
})
@app.route('/delete_data', methods=['DELETE'])
@login_required
def delete_data():
# Delete user data
db.session.delete(current_user)
db.session.commit()
# Log the action
action = f"User {current_user.email} requested data deletion."
new_log = AuditLog(user_id=current_user.id, action=action)
db.session.add(new_log)
db.session.commit()
flash("Your data has been deleted", "success")
return redirect(url_for('logout'))
@app.route('/logout')
@login_required
def logout():
logout_user()
return redirect(url_for('index'))
Explanation:
- Access Data: The
/access_data
endpoint allows users to view their encrypted data, after decrypting it. - Delete Data: The
/delete_data
endpoint allows users to request deletion of their account and data, and it logs this action in the AuditLog table.
Step 5: Audit Log
Whenever a user accesses or deletes their data, we log the action in an AuditLog
table for compliance purposes.
Implement Audit Logging
In the /delete_data
and /access_data
endpoints above, actions are logged in the AuditLog
table, which tracks who did what and when.
pythonCopy code# Log the action in the database
new_log = AuditLog(user_id=current_user.id, action="User requested data deletion.")
db.session.add(new_log)
db.session.commit()
Leave a Reply