《写给前端的python应用指南》系列:
- (一)快速构建 Web 服务器 - Flask vs Node.js 对比
- (二)深入Flask:理解Flask的应用结构与模块化设计
- (三)Django vs Flask:哪种框架适合构建你的下一个Web应用?
- (四)Django实战:创建一个简单的博客系统
- (五)用FastAPI快速构建高性能API
在构建现代Web应用时,用户认证与授权是非常重要的部分。无论是通过用户名和密码登录,还是通过OAuth2、JWT等方式进行身份验证,确保只有授权的用户可以访问敏感数据是每个API设计的核心。本篇博文将详细介绍如何使用Flask和Django构建RESTful API,并实现用户认证与授权功能,包括JWT(JSON Web Tokens)的使用。
一、概述
RESTful API通常用于前后端分离的应用,用户认证与授权机制用于保护API,使得只有经过认证的用户才能访问特定的资源。JWT(JSON Web Token)作为一种轻量级的认证方式,广泛应用于前后端分离的Web应用中。
在本文中,我们将分别使用Flask和Django实现:
- 用户注册
- 用户登录(并生成JWT)
- 保护需要授权的API(通过JWT)
二、Flask实现用户认证与授权
Flask是一个轻量级Web框架,非常适合用来快速构建RESTful API。我们将通过Flask和Flask-JWT-Extended扩展来实现JWT认证。
2.1 安装依赖
首先,我们需要安装Flask和Flask-JWT-Extended。
pip install flask flask-jwt-extended flask-sqlalchemy
2.2 创建Flask应用
我们将创建一个简单的Flask应用,包含用户注册、登录和JWT认证的功能。
- 初始化Flask应用:
from flask import Flask, request, jsonify
from flask_sqlalchemy import SQLAlchemy
from flask_jwt_extended import JWTManager, create_access_token, jwt_required, get_jwt_identityapp = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///users.db' # 使用SQLite数据库
app.config['JWT_SECRET_KEY'] = 'your_jwt_secret_key' # JWT的密钥db = SQLAlchemy(app)
jwt = JWTManager(app)
- 创建用户模型:
我们将创建一个用户模型,用户将具有username
和password
字段。
class User(db.Model):id = db.Column(db.Integer, primary_key=True)username = db.Column(db.String(80), unique=True, nullable=False)password = db.Column(db.String(120), nullable=False)def __repr__(self):return f'<User {self.username}>'
- 用户注册:
用户注册时,我们将验证输入,并将密码进行哈希处理后存入数据库。
from werkzeug.security import generate_password_hash@app.route('/register', methods=['POST'])
def register():data = request.get_json()username = data.get('username')password = data.get('password')# 检查用户是否已存在if User.query.filter_by(username=username).first():return jsonify({"msg": "User already exists"}), 400# 哈希处理密码hashed_password = generate_password_hash(password, method='sha256')new_user = User(username=username, password=hashed_password)db.session.add(new_user)db.session.commit()return jsonify({"msg": "User created successfully"}), 201
- 用户登录并生成JWT:
用户登录时,我们验证用户名和密码是否匹配,若匹配则返回一个JWT。
from werkzeug.security import check_password_hash@app.route('/login', methods=['POST'])
def login():data = request.get_json()username = data.get('username')password = data.get('password')user = User.query.filter_by(username=username).first()if user and check_password_hash(user.password, password):access_token = create_access_token(identity=username)return jsonify(access_token=access_token), 200else:return jsonify({"msg": "Invalid credentials"}), 401
- 受保护的API:
我们使用@jwt_required()
装饰器来保护需要授权的API。用户必须在请求头中提供有效的JWT才能访问这些API。
@app.route('/protected', methods=['GET'])
@jwt_required()
def protected():current_user = get_jwt_identity() # 获取当前用户的身份信息return jsonify(logged_in_as=current_user), 200
- 运行Flask应用:
if __name__ == '__main__':db.create_all() # 创建数据库表app.run(debug=True)
2.3 测试Flask API
你可以使用Postman或者curl
工具来测试这些API接口:
-
注册用户:
POST /register
- 请求体:
{"username": "john", "password": "password123"}
- 响应:
{"msg": "User created successfully"}
- 请求体:
-
用户登录:
POST /login
- 请求体:
{"username": "john", "password": "password123"}
- 响应:
{"access_token": "jwt_token_here"}
- 请求体:
-
访问受保护的API:
GET /protected
- 请求头:
Authorization: Bearer <jwt_token_here>
- 响应:
{"logged_in_as": "john"}
- 请求头:
三、Django实现用户认证与授权
Django是一个功能强大的Web框架,适用于构建复杂的Web应用。在Django中实现JWT认证,我们通常会使用djangorestframework
和djangorestframework-simplejwt
这两个库来进行集成。
3.1 安装依赖
首先,我们需要安装Django、Django REST framework以及JWT相关库。
pip install django djangorestframework djangorestframework-simplejwt
3.2 创建Django项目和应用
django-admin startproject myproject
cd myproject
python manage.py startapp accounts
3.3 配置Django项目
在myproject/settings.py
中,添加rest_framework
和accounts
到INSTALLED_APPS
:
INSTALLED_APPS = [...'rest_framework','accounts',
]
然后,配置JWT设置:
REST_FRAMEWORK = {'DEFAULT_AUTHENTICATION_CLASSES': ['rest_framework_simplejwt.authentication.JWTAuthentication',],
}
3.4 创建用户模型和序列化器
我们将在accounts/models.py
中创建用户模型,并在accounts/serializers.py
中创建序列化器。
- 创建用户模型:
在accounts/models.py
文件中,我们可以使用Django的默认用户模型或者自定义一个用户模型:
from django.contrib.auth.models import AbstractUserclass User(AbstractUser):pass
- 创建序列化器:
在accounts/serializers.py
文件中,我们为用户注册和登录创建序列化器:
from rest_framework import serializers
from django.contrib.auth.models import Userclass UserSerializer(serializers.ModelSerializer):class Meta:model = Userfields = ['username', 'password']def create(self, validated_data):user = User.objects.create_user(**validated_data)return user
3.5 创建视图和URL路由
在accounts/views.py
中,我们使用APIView
来处理注册、登录以及JWT认证。
- 用户注册视图:
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from .serializers import UserSerializerclass RegisterView(APIView):def post(self, request):serializer = UserSerializer(data=request.data)if serializer.is_valid():serializer.save()return Response({"msg": "User created successfully"}, status=status.HTTP_201_CREATED)return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
- 用户登录视图(获取JWT):
from rest_framework_simplejwt.tokens import RefreshTokenclass LoginView(APIView):def post(self, request):username = request.data.get("username")password = request.data.get("password")user = authenticate(username=username, password=password)if user:refresh = RefreshToken.for_user(user)access_token = str(refresh.access_token)return Response({"access_token": access_token}, status=status.HTTP_200_OK)return Response({"msg": "Invalid credentials"}, status=status.HTTP_401_UNAUTHORIZED)
- 受保护的视图:
from rest_framework.permissions import IsAuthenticated
from rest_framework.views import APIViewclass ProtectedView(APIView):permission_classes = [IsAuthenticated]def get(self, request):return Response({"msg": "You have access to this protected view."}, status=status.HTTP_200_OK)
3.6 配置URL路由
在accounts/urls.py
中,配置相应的路由:
from django.urls import path
from .views import RegisterView, LoginView, ProtectedViewurlpatterns = [path('register/', RegisterView.as_view(), name='register'),path('login/', LoginView.as_view(), name='login'),path('protected/', ProtectedView.as_view(), name='protected'),
]
在myproject/urls.py
中,包含accounts/urls.py
:
from django.contrib import admin
from django.urls import path, includeurlpatterns = [path('admin/', admin.site.urls),path('api/accounts/', include('accounts.urls')),
]
3.7 运行Django项目
python manage.py runserver
3.8 测试Django API
使用Postman或curl
测试以下API:
- 注册用户:
POST /api/accounts/register/
- 用户登录:
POST /api/accounts/login/
- 访问受保护的API:
GET /api/accounts/protected/
(需要JWT令牌)
四、总结
通过本文的示例,我们分别展示了如何使用Flask和Django实现用户认证与授权,保护RESTful API。两种框架都支持JWT认证,但在实现上有所不同:
- Flask适合轻量级项目,灵活且简洁。
- Django则更适合复杂的应用,具有更强的功能和更好的扩展性。
无论你选择Flask还是Django,它们都能提供高效、安全的认证方式,并能帮助你快速构建可扩展的RESTful API。希望本文的示例能帮助你在实际项目中更好地实现用户认证与授权功能!