1 常用的用户验证方法

  • 基本身份验证(Basic Authentication): 这是最简单的身份验证方式之一。客户端在请求头中包含用户名和密码的 Base64 编码
  • Token 身份验证: 使用 Token 身份验证,客户端在请求中提供一个令牌(token),服务器在收到请求后验证令牌的有效性。
  • OAuth 认证: OAuth 是一种流行的开放标准,用于授权第三方应用程序访问用户的数据。
  • JSON Web Token(JWT): JWT 是一种用于在网络应用之间安全传递声明的开放标准。JWT 由三部分组成:头部、载荷和签名。
  • SSL/TLS: 使用 SSL/TLS 加密协议来保护通信是保护 API 免受未经授权访问的重要手段之一,这也是常用的 Session/Cookie 方法。

2 选型

由于我的服务端基本已用 Django 写好,自带比较完善的用户管理,使用 Session/Cookie 方法,修改最小,理论上只需要在请求时设置 withCredentials 即可。

但由于我的前后端分离,且使用一个后端和多个前端的模式,因此产生了跨域请求问题。需要将 http 改为 https,但考虑到我后面会开源,加密协议在二次开发和调试时会很麻烦。

最终,我选择了 JWT 方案,也就是大家常用的传 token 方式。具体使用的是 Django 的第三方库:django-rest-knox。看起来并不困难,通过 gpt-4o 提供的示例进行操作,然后自己解决了一些问题,最后成功实现。记录如下,并讨论一下在使用这种较为小众工具时,大模型辅助编程遇到的一些问题。

3 具体实现

3.1 后端

3.1.1 源码地址

https://github.com/jazzband/django-rest-knox/ 1.1K Star

3.1.2 安装 django-rest-knox

1
$ pip install django-rest-knox

3.1.3 配置认证类

修改 settings.py

1
2
3
4
5
6
7
8
9
10
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'knox.auth.TokenAuthentication',
)
}

INSTALLED_APPS = [
# other apps
'knox',
]

3.1.4 重写登录方法

修改 views.py

1
2
3
4
5
6
7
8
9
class LoginView(KnoxLoginView):
permission_classes = (permissions.AllowAny,)

def post(self, request, format=None):
serializer = AuthTokenSerializer(data=request.data)
serializer.is_valid(raise_exception=True)
user = serializer.validated_data['user']
login(request, user)
return super(LoginView, self).post(request, format=None)

3.1.5 为各个方法加验证

修改 views.py,在需要用户验证的方法前加装饰器

1
2
3
4
5
@api_view(['POST'])
@authentication_classes([TokenAuthentication])
@permission_classes([IsAuthenticated])
def test(request):
...

3.1.6 声明接口

修改 urls.py

1
2
3
4
5
6
7
from knox import views as knox_views

urlpatterns = [
path(r'api/auth/login/', LoginView.as_view(), name='knox_login'),
path(r'api/auth/logout/', knox_views.LogoutView.as_view(), name='knox_logout'),
path(r'api/auth/logoutall/', knox_views.LogoutAllView.as_view(), name='knox_logoutall'),
]

3.2 模拟前端调试

3.2.1 调用登录返回 token

1
$ curl -X POST \ -H "Content-Type: application/json" \ -d '{"username": "your_username", "password": "your_password"}' \ http://localhost:8000/api/auth/login/

3.2.2 带 token 访问方法

1
2
3
$ curl -X POST \
-H "Authorization: token 具体TOKEN" \
http://localhost:8000/test/