django 用户认证之四:jwt用户认证

因为 restframework 的 token 认证存在一些缺陷,所以现在一般都使用 jwt 用户认证。

 

JWT全称 Json Web Token ,

原理 :

服务器里面存储一个加密算法的 密匙, 然后有用户登陆时, 通过用户提供的信息,

用这个 密匙 生成一个 token 返回给 前端,前端把这个 token 保存到本地,然后下次请求

数据时带上这个 token ,后端获取到这个 token 后,通过密匙对 token 进行验证,

判断用户是否登录,如果验证 通过则解析出这个 token 对应的用户的信息,允许他访问资源。

如果验证不通过则给出错误提示。

 

这样 token 就不需要存储到服务器,数据读写、存储的压力会小很多,

虽然计算压力会增加(该模式的token 验证需要计算)。

还有就是你如果做的是分布式系统, 只要把这个 密匙 给另外一个系统, 另外一个系统也能

验证该用户是否登录以及解析出该用户的信息, 这样 就不需要不同的系统对 session 进行同步。

 

 Django REST Framework : https://github.com/GetBlimp/django-rest-framework-jwt

文档 : http://getblimp.github.io/django-rest-framework-jwt/

 

安装 : pip install djangorestframework-jwt

 

使用 :

1.在 django 的settings.py 中的 REST_FRAMEWORK 中添加以下代码进行配置

 

'rest_framework_jwt.authentication.JSONWebTokenAuthentication',

这个东西的作用是将接收到的 token 解析成用户信息,跟其他的 Middleware 类似。

 

2.在 django 的url 中配置一个路由

from rest_framework_jwt.views import obtain_jwt_token urlpatterns = [ (r'^api-token-auth/', obtain_jwt_token), ]

 

现在可以通过向 http://127.0.0.1:8000/api-token-auth/ 这个url 发送 post 请求并且携带

{

"username":"admin",

"password":"admin123456"

}

这个方式来获取 token ,发送请求后,他会调用 django 的 auth 查询数据库比对

用户名和密码是否正确,正确就返回一个 token 。

{

token:

"eyJhbGciOiAiSFMyNTYiLCAidHlwIjogIkpXVCJ9.eyJpc3MiOiAibW96aWxsYXpnLmNvbSIsICJmb28iOiAiYmFyIiwgInVzZXJfaWQiOiAxLCAiZXhwIjogMTQzNTA1NTExN30"

}

这个 token . 的前面是 base64 加密的用户信息 , 后面的是我们的签名(签名是通过密匙生成的,主要靠这个保证安全), https://blog.csdn.net/offbye/article/details/47617409

 

前端如何使用这个 token ? 【把他放到 http 的 header 里面】

对于客户端进行身份验证,令牌密钥应该包含在AuthorizationHTTP头中。关键字应以字符串文字“JWT”为前缀,用空格分隔两个字符串。例如:

Authorization: JWT 9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b

 

前端解析 token 的结果 :

如下, 我把我的 token 直接拿去 base64 解码,

 

 

 

 

 

前面两个点的内容就可以解析出我用户的一些基本信息 。

 

使用 httpie 携带 token 请求数据 :

http http://192.168.1.102:8001/user/ Authorization:'JWT eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1MjgwMzIxNjAsImVtYWlsIjpudWxsLCJ1c2VybmFtZSI6InhpYW9taW5nIiwidXNlcl9pZCI6Mn0.aIH8FeNIWlOOYzOog5XoENsFUkD0hrd_XHUHZ8qxZdQ'

 

http http://192.168.1.175:8001/user/ Authorization:'JWT eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxLCJ1c2VybmFtZSI6ImFkbWluIiwiZXhwIjoxNTI3NTAwODU1LCJlbWFpbCI6IiJ9.5aGL1zVrH-y5yFKfOGHGSaTU10hLbMFFDWTzeW3i05M'

 

此时我在我的 url 请求的头部添加这个之后,访问我的 restful api 资源了,后台获取到这个 token 后

还不能解析出这个 token 对应的用户是谁,跟 token 的实现方法一样。

前端一般把 username 和 token 保存到 cookie 里面,然后

 

 

----------------------------------------

 

存在的问题 :

登录时输入【用户名】和【密码】,会调用 django 的auth 去查询 用户名和密码是否匹配,匹配

再生产 token 并返回,这样的话如果我输入手机号登录就会不成功。

 

所以这里就需要自定义 django 的用户认证函数:

 

【自定义用户认证】:

1.可以在 user 这个 app 的 view 里面编写用户认证视图

2.这个自定义的视图要继承自 django 的用户认证视图 ModelBackend ,重写他的 authenticate 方法

(这里我们通过 get_user_model() 方法来获取User表的model。)

3.自定义完成后需要到 django 的settings.py 里面进行配置 (类似我们的用户认证模型)

 

from django.contrib.auth.backends import ModelBackend

from django.db.models import Q

from django.contrib.auth import get_user_model

 

User = get_user_model()

 

class CustomBackend(ModelBackend):

"""

自定义用户认证

1. 编写继承自 django 的用户认证视图 ModelBackend 的视图

2.重写他的 authenticate 方法

3.在 settings.py 里面将这个用户校验类定义为默认的校验类(参考定义默认的用户模型)

AUTHENTICATION_BACKENDS = (

'users.views.CustomBackend',

)

"""

def authenticate(self, request, username=None, password=None, **kwargs):

"""

 

:param request: 用户发起登陆请求时的 request

:param username: 用户提交的用于登陆的 username(可以是任何我们想要作为验证的东西,

常用:用户名、邮箱、手机号码,如果我们愿意,用用户的生日登陆也是可以做到的)

:param password: 用户提交的用于登陆的 password

:param kwargs:

:return: 校验通过返回 user 这个 queset 对象,不通过返回 None

"""

try:

# 尝试将用户输入的 username 跟我们用户表中的 用户名 或则 手机号码进行匹配

# 这里就是我的手机号码登陆能成功的关键

user = User.objects.get(Q(username=username) | Q(mobile=username))

# 如果获取到了对应的用户而且用 django 的 check_password 校验密码通过

if user.check_password(password):

# 返回 user 这个 queset 对象

return user

except Exception as e:

return None

 

此时,用户登陆算是完成了。

----------------------------------------------------

总结 :

用户通过 post 方法发送手机号和密码给服务器,服务器接收到后先通过 get_user_model()

获取自定义的用户表,然后通过自定义的 用户认证方法校验 用户名 和密码是否匹配,

校验成功就会给前端 返回一个 token ,前端就把这个 token 保存到 cookie 里面,

以后访问数据的时候 就会在 cookie 里面携带这个 token ,后端接收到 这个 token 之后,

通过 'rest_framework_jwt.authentication.JSONWebTokenAuthentication', 解析出

对应的用户,然后认为他已经登录了,允许他访问资源并执行相应的业务逻辑。

 

JWT 设置 (过期时间 等)

在 django 的 settings.py 中添加以下内容 :

 

import datetime

 

JWT_AUTH = {

'JWT_EXPIRATION_DELTA': datetime.timedelta(days=7), # 过期时间

'JWT_AUTH_HEADER_PREFIX': 'JWT', # 在 http头 中的 开头, 默认为 JWT ,可以修改

# 对应这个东西 Authorization: JWT 9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b

'JWT_SECRET_KEY': settings.SECRET_KEY, # jwt 生成 token 所使用的 key 。

}

 

 

================================

两个系统只要 key 相同,用同一个user表,server1生成的 token 在server2就能验证通过。

设置 key :

django 的 settings.py 中的 SECRET_KEY = 'abcdef'

 

token 的 校验 会去查找 user 表!!!!

================================

 

django-rest-framework-jwt token 怎么解码得到用户名

 

先 

from rest_framework_jwt.utils import jwt_decode_handler

jwt_decode_handler(token)

 

===================================================

 

jwt生成token :

 

1. 获取 user

user = self.perform_create(serializer)

2. 通过获取的 user 生成 payload

payload = jwt_payload_handler(user)

3. 通过生成的 payload 生成 token

re_dict["token"] = jwt_encode_handler(payload)

 

你可能感兴趣的:(django框架)