DRF -- Jwt认证使用流程
1. jwt (django_1.10及以下)
1. Jwt介绍
1.1 构成
Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519).
该token被设计为紧凑且安全的,特别适用于分布式站点的单点登录(SSO)场景。JWT的声明一般被用来在身份提供
者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源,也可以增加一些额外的其它业务逻辑所
必须的声明信息,该token也可直接被用于认证,也可被加密
JWT就是一段字符串,由三段信息构成的,将这三段信息文本用.链接一起就构成了Jwt字符串。就像这样:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ
第一部分我们称它为头部(header),第二部分我们称其为载荷(payload, 类似于飞机上承载的物品),第三部分是签证(signature).
1. header
jwt的头部承载两部分信息:
	1. 声明类型,这里是jwt
	2. 声明加密的算法 通常直接使用 HMAC SHA256
定义一个header
{
  'typ': 'JWT',
  'alg': 'HS256'
}
然后将头部Json进行base64加密(该加密是可以对称解密的),构成了第一部分.
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9
2. payload
载荷就是存放有效信息的地方。这个名字像是特指飞机上承载的货品,这些有效信息包含三个部分
	1. 标准中注册的声明
		a. iss: jwt签发者
		b. sub: jwt所面向的用户
         c. aud: 接收jwt的一方
         d. exp: jwt的过期时间,这个过期时间必须要大于签发时间
         e. nbf: 定义在什么时间之前,该jwt都是不可用的.
         f. iat: jwt的签发时间
         g: jti: jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击。
	2. 公共的声明
		a. 公共的声明可以添加任何的信息,一般添加用户的相关信息或其他业务需要的必要信息.
         b. 但不建议添加敏感信息,因为该部分在客户端可解密.
	3. 私有的声明
		a. 私有声明是提供者和消费者所共同定义的声明,
		b. 一般不建议存放敏感信息,因为base64是对称解密的,意味着该部分信息可以归类为明文信息。
定义一个payload:
{
  "sub": "1234567890",
  "name": "John Doe",
  "admin": true
}
然后将其进行base64加密,得到JWT的第二部分。
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9
3. signature
JWT的第三部分是一个签证信息,这个签证信息由三部分组成:
	1. header (base64后的)
	2. payload (base64后的)
	3. secret
这个部分需要base64加密后的header和base64加密后的payload使用.连接组成的字符串,然后通过header中声明的加密方式进行加盐secret组合加密,然后就构成了jwt的第三部分。
# javascript如果要模拟生成你的jwttoken,可能可以采用以下代码生成[注意:伪代码]
var encodedString = base64UrlEncode(header) + '.' + base64UrlEncode(payload);
var signature = HMACSHA256(encodedString, 'secret'); // TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ
将这三部分用.连接成一个完整的字符串,构成了最终的jwt:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ
**
1.2 注意事项
secret是保存在服务器端的,jwt的签发生成也是在服务器端的,secret就是用来进行jwt的签发和jwt的验证,所以,它就是你服务端的私钥,在任何场景都不应该流露出去。一旦客户端得知这个secret, 那就意味着客户端是可以自我签发jwt了
2. 模块下载
pip install djangorestframework-jwt -i https://mirrors.aliyun.com/pypi/simple
3. 全局配置JWT
项目目录/settings.py
REST_FRAMEWORK = {
    'DEFAULT_PERMISSION_CLASSES': (
        'rest_framework.permissions.IsAuthenticated',
    ),
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
        'rest_framework.authentication.SessionAuthentication',
        'rest_framework.authentication.BasicAuthentication',
    ),
}
JWT_AUTH = {
    'JWT_ENCODE_HANDLER': 'rest_framework_jwt.utils.jwt_encode_handler',
    'JWT_DECODE_HANDLER': 'rest_framework_jwt.utils.jwt_decode_handler',
    'JWT_PAYLOAD_HANDLER': 'rest_framework_jwt.utils.jwt_payload_handler',
    'JWT_PAYLOAD_GET_USER_ID_HANDLER': 'rest_framework_jwt.utils.jwt_get_user_id_from_payload_handler',
    'JWT_RESPONSE_PAYLOAD_HANDLER': 'baler.utils.jwt_response_payload_handler',  # 默认登录成功只有token,可以自定义登录成功的返回数据
    'JWT_SECRET_KEY': SECRET_KEY,
    'JWT_GET_USER_SECRET_KEY': None,
    'JWT_PUBLIC_KEY': None,
    'JWT_PRIVATE_KEY': None,
    'JWT_ALGORITHM': 'HS256',
    'JWT_VERIFY': True,
    'JWT_VERIFY_EXPIRATION': True,
    'JWT_LEEWAY': 0,
    'JWT_EXPIRATION_DELTA': datetime.timedelta(days=365),
    'JWT_AUDIENCE': None,
    'JWT_ISSUER': None,
    'JWT_ALLOW_REFRESH': False,
    'JWT_REFRESH_EXPIRATION_DELTA': datetime.timedelta(days=365),
    'JWT_AUTH_HEADER_PREFIX': 'Bearer',  # token前缀 如token的值必须以Bearer开头+一个空格+token串,如Bearer df1lmvc...
    'JWT_AUTH_COOKIE': None,
}
4. 手动生成Jwt的内置方法
from rest_framework_jwt.settings import api_settings
jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER
payload = jwt_payload_handler(user)
token = jwt_encode_handler(payload)
5. 使用JWT内置认证接口
1. 路由
obtain_jwt_token 是 Jwt 自己实现的登录视图,可以直接拿来用
app/urls.py
from rest_framework_jwt.views import obtain_jwt_token
urlpatterns = [
	path(r'authorizations/', obtain_jwt_token, name='authorizations'),
    # url可以修改
    # path(r'login/', obtain_jwt_token, name='login'),
]
2. 自定义验证成功的响应数据
scadasoft/utils.py
def jwt_response_payload_handler(token, user=None, request=None):
    """
    自定义jwt认证成功返回数据
    """
    return {
        'token': token,
        'id': user.id,
        'username': user.username
    }
6. 单独配置JWT
app/views.py
class StationInfoView(APIView):
    """
    空压站
    """
    authentication_classes = [JSONWebTokenAuthentication]   # 配置Jwt认证类,如果全局配置了这里可以省略,如果某个视图不想认证,如LoginView 可以设置为 authentication_classes = []
    permission_classes = [IsAuthenticated]   	# 配置权限,登录成功才可以访问本接口,同上
    def get(self, request):
        station_objs = air_compressor_station.objects.filter(
            existence=True,
        )
        data_count = station_objs.count()
        result = StationSerializer(station_objs, many=True)
        return PublicRes(data=result.data, data_count=data_count)
2. simplejwt(django_1.10以上)
2.0 官方网站
https://django-rest-framework-simplejwt.readthedocs.io/zh-hans/latest/settings.html
2.1 安装
pip install djangorestframework-simplejwt
2.2 配置
settings.py
# settings.py
INSTALLED_APPS = [
	...
    'rest_framework', 
    'rest_framework_simplejwt', 
]
REST_FRAMEWORK = {
    'DEFAULT_PERMISSION_CLASSES': (
        'rest_framework.permissions.IsAuthenticated',
    ),
    # 认证类
    # 先进行token的验证,如果没有携带token就进行session认证,如果没有session就就基本认证
    # 认证顺序是从上到下,需要哪个加哪个
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework_simplejwt.authentication.JWTAuthentication',
        'rest_framework.authentication.SessionAuthentication',
        'rest_framework.authentication.BasicAuthentication',
    ),
}
SIMPLE_JWT = {
    # token有效时长(返回的 access 有效时长)
    'ACCESS_TOKEN_LIFETIME': datetime.timedelta(seconds=30),
    # token刷新的有效时间(返回的 refresh 有效时长)
    'REFRESH_TOKEN_LIFETIME': datetime.timedelta(seconds=20),
}
urls.py
from rest_framework_simplejwt.views import TokenObtainPairView, TokenRefreshView, TokenVerifyView
urlpatterns = [
    path('authorizations/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
    path('refresh/', TokenRefreshView.as_view(), name='token_refresh'),
    path('verify/', TokenVerifyView.as_view(), name='token_verify'),
]
2.3 其他配置
settings.py
# Django project settings.py
from datetime import timedelta
...
SIMPLE_JWT = {
    # datetime.timedelta指定访问令牌有效时间的对象。该timedelta值在令牌生成期间添加到当前 UTC 时间以获得令牌的默认“exp”声明值。
    "ACCESS_TOKEN_LIFETIME": timedelta(minutes=5),
    # datetime.timedelta指定刷新令牌有效时间的对象。该timedelta值在令牌生成期间添加到当前 UTC 时间以获得令牌的默认“exp”声明值。
    "REFRESH_TOKEN_LIFETIME": timedelta(days=1),
    # 设置为True时,如果将刷新令牌提交给 TokenRefreshView,则新的刷新令牌将与新的访问令牌一起返回。这个新的刷新令牌将通过 JSON 响应中的“刷新”键提供。新的刷新令牌将有一个更新的到期时间,该时间是通过将设置中的 timedelta 添加REFRESH_TOKEN_LIFETIME 到发出请求时的当前时间来确定的。如果黑名单应用程序正在使用中并且BLACKLIST_AFTER_ROTATION设置为True,则提交到刷新视图的刷新令牌将被添加到黑名单中。
    "ROTATE_REFRESH_TOKENS": False,
    # 设置为True时,如果黑名单应用程序正在使用且设置设置True为 ,则提交给 的刷新令牌 将被添加到黑名单。您需要在设置文件中添加才能使用此设置。 TokenRefreshViewROTATE_REFRESH_TOKENSTrue’rest_framework_simplejwt.token_blacklist’,INSTALLED_APPS
    "BLACKLIST_AFTER_ROTATION": False,
    "UPDATE_LAST_LOGIN": False,
    "ALGORITHM": "HS256",
    "SIGNING_KEY": settings.SECRET_KEY,
    "VERIFYING_KEY": "",
    "AUDIENCE": None,
    "ISSUER": None,
    "JSON_ENCODER": None,
    "JWK_URL": None,
    "LEEWAY": 0,
    "AUTH_HEADER_TYPES": ("Bearer",),
    "AUTH_HEADER_NAME": "HTTP_AUTHORIZATION",
    "USER_ID_FIELD": "id",
    "USER_ID_CLAIM": "user_id",
    "USER_AUTHENTICATION_RULE": "rest_framework_simplejwt.authentication.default_user_authentication_rule",
    "AUTH_TOKEN_CLASSES": ("rest_framework_simplejwt.tokens.AccessToken",),
    "TOKEN_TYPE_CLAIM": "token_type",
    "TOKEN_USER_CLASS": "rest_framework_simplejwt.models.TokenUser",
    "JTI_CLAIM": "jti",
    "SLIDING_TOKEN_REFRESH_EXP_CLAIM": "refresh_exp",
    "SLIDING_TOKEN_LIFETIME": timedelta(minutes=5),
    "SLIDING_TOKEN_REFRESH_LIFETIME": timedelta(days=1),
    "TOKEN_OBTAIN_SERIALIZER": "rest_framework_simplejwt.serializers.TokenObtainPairSerializer",
    "TOKEN_REFRESH_SERIALIZER": "rest_framework_simplejwt.serializers.TokenRefreshSerializer",
    "TOKEN_VERIFY_SERIALIZER": "rest_framework_simplejwt.serializers.TokenVerifySerializer",
    "TOKEN_BLACKLIST_SERIALIZER": "rest_framework_simplejwt.serializers.TokenBlacklistSerializer",
    "SLIDING_TOKEN_OBTAIN_SERIALIZER": "rest_framework_simplejwt.serializers.TokenObtainSlidingSerializer",
    "SLIDING_TOKEN_REFRESH_SERIALIZER": "rest_framework_simplejwt.serializers.TokenRefreshSlidingSerializer",
}
    python防脱发技巧

                
            
        
浙公网安备 33010602011771号