(四) DRF认证, 权限, 节流
一、Token 认证的来龙去脉
摘要
Token 是在服务端产生的。如果前端使用用户名/密码向服务端请求认证,服务端认证成功,那么在服务端会返回 Token 给前端。前端可以在每次请求的时候带上 Token 证明自己的合法地位
为什么要用 Token?
要回答这个问题很简单——因为它能解决问题!
可以解决哪些问题呢?
Token 完全由应用管理,所以它可以避开同源策略
Token 可以避免 CSRF 攻击
Token 可以是无状态的,可以在多个服务间共享
Token 是在服务端产生的。如果前端使用用户名/密码向服务端请求认证,服务端认证成功,那么在服务端会返回 Token 给前端。前端可以在每次请求的时候带上 Token 证明自己的合法地位。如果这个 Token 在服务端持久化(比如存入数据库),那它就是一个永久的身份令牌。
时序图表示
使用 Token 的时序图如下:
1)登录
2)业务请求
关于token的详细信息,请参考链接:
https://blog.csdn.net/maxushan001/article/details/79222271
二、DRF 认证
DRF认证源码流程
https://www.cnblogs.com/derek1184405959/p/8712206.html
表
定义一个用户表和一个保存用户Token的表,models.py完整代码下:
from django.db import models
# 用户信息表
class UserInfo(models.Model):
username = models.CharField(max_length=, unique=True)
password = models.CharField(max_length=) type = models.SmallIntegerField(
choices=((, '普通用户'), (, 'VIP用户')),
default=
) # token
class Token(models.Model):
token = models.CharField(max_length=)
user = models.OneToOneField(to='UserInfo',on_delete=models.CASCADE)
token单独分一个表,是因为它是在原有用户表的功能扩展。不能对一个表无限的增加字段,否则会导致表原来越臃肿
在前后端分离的架构中,前端使用ajax请求发送给后端,它不能使用cookie/session。那么后端怎么知道这个用户是否登录了,是否是VIP用户呢?使用token就可以解决这个问题!
视图
def get_token_code(username):
"""
根据用户名和时间戳生成用户登陆成功的随机字符串
:param username: 字符串格式的用户名
:return: 字符串格式的Token
"""
import time
import hashlib
timestamp = str(time.time()) # 当前时间戳
m = hashlib.md5(bytes(username, encoding='utf8'))
m.update(bytes(timestamp, encoding='utf8')) # update必须接收一个bytes
return m.hexdigest() # 登陆视图
class LoginView(APIView):
"""
登陆检测视图
. 接收用户发过来(POST)的用户名和密码数据
. 校验用户名密码是否正确
- 成功就返回登陆成功(发Token)
- 失败就返回错误提示
""" def post(self, request): # POST请求
res = {"code": }
# 从post里面取数据
username = request.data.get("username")
password = request.data.get("password")
# 去数据库查询
user_obj = models.UserInfo.objects.filter(
username=username,
password=password,
).first()
if user_obj:
# 登陆成功
# 生成Token
token = get_token_code(username)
# 将token保存
# 用user=user_obj这个条件去Token表里查询
# 如果有记录就更新defaults里传的参数, 没有记录就用defaults里传的参数创建一条数据
models.Token.objects.update_or_create(defaults={"token": token}, user=user_obj)
# 将token返回给用户
res["token"] = token
else:
# 登录失败
res["code"] =
res["error"] = '用户名或密码错误'
return Response(res)
路由
from django.conf.urls import url
from app01 import views urlpatterns = [
url(r'login/$', views.LoginView.as_view()),
]
使用postman发送post登录
查看返回结果,code为0表示登录成功,并返回一个token
查看表app01_token,就会多一条记录
定义一个认证类
在app01(应用名)目录下创建目录utils,在此目录下创建auth.py
from rest_framework.authentication import BaseAuthentication
from app01 import models
from rest_framework.exceptions import AuthenticationFailed class MyAuth(BaseAuthentication): def authenticate(self, request): # 必须要实现此方法
if request.method in ['POST', 'PUT', 'DELETE']:
token = request.data.get("token")
# 去数据库查询有没有这个token
token_obj = models.Token.objects.filter(token=token).first()
if token_obj:
# token_obj有2个属性,详见models.py中的Token。
# return后面的代码,相当于分别赋值。例如a=,b=2等同于a,b=,
# return多个值,返回一个元组
#在rest framework内部会将这两个字段赋值给request,以供后续操作使用
return token_obj.user, token # self.user, self.token = token_obj.user, token
else:
raise AuthenticationFailed('无效的token')
else:
return None, None
视图级别认证
修改views.py,完整代码如下:
from django.shortcuts import render, HttpResponse
from app01 import models
from app01 import app01_serializers # 导入自定义的序列化
from rest_framework.viewsets import ModelViewSet
from rest_framework.views import APIView
from rest_framework.response import Response
from app01.utils.auth import MyAuth # app01.utils.auth表示app01目录下的utils下的auth.py # Create your views here. # 生成Token的函数
def get_token_code(username):
"""
根据用户名和时间戳生成用户登陆成功的随机字符串
:param username: 字符串格式的用户名
:return: 字符串格式的Token
"""
import time
import hashlib
timestamp = str(time.time()) # 当前时间戳
m = hashlib.md5(bytes(username, encoding='utf8'))
m.update(bytes(timestamp, encoding='utf8')) # update必须接收一个bytes
return m.hexdigest() # 登陆视图
class LoginView(APIView):
"""
登陆检测视图
. 接收用户发过来(POST)的用户名和密码数据
. 校验用户名密码是否正确
- 成功就返回登陆成功(发Token)
- 失败就返回错误提示
""" def post(self, request): # POST请求
res = {"code": }
# 从post里面取数据
username = request.data.get("username")
password = request.data.get("password")
# 去数据库查询
user_obj = models.UserInfo.objects.filter(
username=username,
password=password,
).first()
if user_obj:
# 登陆成功
# 生成Token
token = get_token_code(username)
# 将token保存
# 用user=user_obj这个条件去Token表里查询
# 如果有记录就更新defaults里传的参数, 没有记录就用defaults里传的参数创建一条数据
models.Token.objects.update_or_create(defaults={"token": token}, user=user_obj)
# 将token返回给用户
res["token"] = token
else:
# 登录失败
res["code"] =
res["error"] = '用户名或密码错误'
return Response(res) class CommentViewSet(ModelViewSet):
queryset = models.Comment.objects.all()
serializer_class = app01_serializers.CommentSerializer
authentication_classes = [MyAuth, ] # 局部使用认证方法MyAuth
发送一个空的post请求,返回结果如下:
发送一个错误的token
返回结果:
注意:这个信息是由raise AuthenticationFailed('无效的token')触发的。
如果想在MyAuth类-->authenticate方法-->代码else中触发别的信息,也同样需要定义raise
全局级别认证
要想让每一个视图都要认证,可以在settings.py中配置
REST_FRAMEWORK = {
# 表示app01-->utils下的auth.py里面的MyAuth类
"DEFAULT_AUTHENTICATION_CLASSES": ["app01.utils.auth.MyAuth", ]
}
修改views.py,注释掉CommentViewSet中的authentication_classes
再次测试上面的3种请求方式,效果同上!
三、DRF权限
权限源码流程
请参考链接:
http://www.cnblogs.com/derek1184405959/p/8722212.html
自定义一个权限类 has_permission
注意:当返回一个对象时,才会触发
什么对象呢?json对象!why?
在CommentViewSet视图中,它会返回一个json数据
http://127.0.0.1:8000/api/comment/ 它会返回一个json列表
http://127.0.0.1:8000/api/comment/1 它会返回一个json对象。
当使用了权限类后,类中有has_permission,就有触发
举例:
在目录app01-->utils下面新建文件permission.py
"""
自定义的权限类
"""
from rest_framework.permissions import BasePermission class MyPermission(BasePermission):
def has_permission(self, request, view):
"""
判断该用户有没有权限
"""
# 判断用户是不是VIP用户
# 如果是VIP用户就返回True
# 如果是普通用户就返回False
print('我要进行自定义的权限判断啦....')
print(request)
print(request.user)
return True
视图级别配置
修改views.py,指定permission_classes
from django.shortcuts import render, HttpResponse
from app01 import models
from app01 import app01_serializers # 导入自定义的序列化
from rest_framework.viewsets import ModelViewSet
from rest_framework.views import APIView
from rest_framework.response import Response
from app01.utils.auth import MyAuth # app01.utils.auth表示app01目录下的utils下的auth.py
from app01.utils.permission import MyPermission # Create your views here. # 生成Token的函数
def get_token_code(username):
"""
根据用户名和时间戳生成用户登陆成功的随机字符串
:param username: 字符串格式的用户名
:return: 字符串格式的Token
"""
import time
import hashlib
timestamp = str(time.time()) # 当前时间戳
m = hashlib.md5(bytes(username, encoding='utf8'))
m.update(bytes(timestamp, encoding='utf8')) # update必须接收一个bytes
return m.hexdigest() # 登陆视图
class LoginView(APIView):
"""
登陆检测视图
. 接收用户发过来(POST)的用户名和密码数据
. 校验用户名密码是否正确
- 成功就返回登陆成功(发Token)
- 失败就返回错误提示
""" def post(self, request): # POST请求
res = {"code": }
# 从post里面取数据
username = request.data.get("username")
password = request.data.get("password")
# 去数据库查询
user_obj = models.UserInfo.objects.filter(
username=username,
password=password,
).first()
if user_obj:
# 登陆成功
# 生成Token
token = get_token_code(username)
# 将token保存
# 用user=user_obj这个条件去Token表里查询
# 如果有记录就更新defaults里传的参数, 没有记录就用defaults里传的参数创建一条数据
models.Token.objects.update_or_create(defaults={"token": token}, user=user_obj)
# 将token返回给用户
res["token"] = token
else:
# 登录失败
res["code"] =
res["error"] = '用户名或密码错误'
return Response(res) class CommentViewSet(ModelViewSet):
queryset = models.Comment.objects.all()
serializer_class = app01_serializers.CommentSerializer
# authentication_classes = [MyAuth, ] # 局部使用认证方法MyAuth
permission_classes = [MyPermission, ] # 局部使用权限方法
发送get请求
查看Pycharm控制台输出:
我要进行自定义的权限判断啦....
<rest_framework.request.Request object at 0x000002576A780FD0>
None
发现用户为None,它没有触发has_permission
访问单个评论,返回单个json对象
查看Pycharm控制台输出:
我要进行自定义的权限判断啦....
<rest_framework.request.Request object at 0x000002576A780FD0>
这是在自定义权限类中的has_object_permission
它触发了has_permission,并输出了一段话
注意:json对象中,它增加一个属性user,值为null。为什么会增加呢?
因为在源码中,Request有个user方法,加 @property。它对返回结果做了在再次封装!
详情,请参考上面的权限源码流程
普通用户
发送post请求,写一个正确的token,用zhang用户的token
查看Pycharm控制台输出:
我要进行自定义的权限判断啦....
<rest_framework.request.Request object at 0x000002576A9852B0>
UserInfo object
此时得到了一个用户对象
修改permission.py,获取用户名以及用户类型
"""
自定义的权限类
"""
from rest_framework.permissions import BasePermission class MyPermission(BasePermission):
def has_permission(self, request, view):
"""
判断该用户有没有权限
"""
# 判断用户是不是VIP用户
# 如果是VIP用户就返回True
# 如果是普通用户就返回False
print('我要进行自定义的权限判断啦....')
print(request)
print(request.user.username)
print(request.user.type)
return True
再次发送同样的post请求,再次查看Pycharm控制台输出
<rest_framework.request.Request object at 0x000001D893AC4048>
zhang
居然得到了zhang和1。为什么呢?为什么request.user.username就能得到用户名呢?
我来大概解释一下,先打开这篇文章:
https://www.cnblogs.com/derek1184405959/p/8712206.html
我引用里面几句话
Request有个user方法,加 @property 表示调用user方法的时候不需要加括号“user()”,可以直接调用:request.user
在rest framework内部会将这两个字段赋值给request,以供后续操作使用
return (token_obj.user,token_obj)
上面的return的值,来源于app01\utils\auth.py里面的MyAuth类中的return token_obj.user, token
简单来说,通过认证之后,它会request进行再次封装,所以调用request.user时,得到了一个对象
这个对象就是执行models.Token.objects.filter(token=token).first()的结果
如果ORM没有查询出结果,它就一个匿名用户!
修改permission.py,如果是VIP返回True,否则返回False
"""
自定义的权限类
"""
from rest_framework.permissions import BasePermission class MyPermission(BasePermission):
def has_permission(self, request, view):
"""
判断该用户有没有权限
"""
# 判断用户是不是VIP用户
# 如果是VIP用户就返回True
# 如果是普通用户就返回False
print('我要进行自定义的权限判断啦....')
# print(request)
print(request.user.username)
print(request.user.type)
if request.user.type == : # 是VIP用户
return True
else:
return False
修改settings.py,关闭全局级别认证
REST_FRAMEWORK = {
# 表示app01-->utils下的auth.py里面的MyAuth类
# "DEFAULT_AUTHENTICATION_CLASSES": ["app01.utils.auth.MyAuth", ]
}
使用VIP用户wang登录
查看返回结果,它返回wang的token
查看表app01_token,它现在有2个记录了
复制zhang的token,发送一条评论
查看返回结果,提示您没有执行此操作的权限
英文看不懂,没关系,定义成中文就行了
修改permission.py,定义message
"""
自定义的权限类
"""
from rest_framework.permissions import BasePermission class MyPermission(BasePermission):
message = '您没有执行此操作的权限!'
def has_permission(self, request, view):
"""
判断该用户有没有权限
"""
# 判断用户是不是VIP用户
# 如果是VIP用户就返回True
# 如果是普通用户就返回False
print('我要进行自定义的权限判断啦....')
# print(request)
print(request.user.username)
print(request.user.type)
if request.user.type == : # 是VIP用户
return True
else:
return False
再次发送,返回结果如下:
VIP用户
将token改成VIP用户测试
查看返回结果
修改permission.py,定义发送类型
"""
自定义的权限类
"""
from rest_framework.permissions import BasePermission class MyPermission(BasePermission):
message = '您没有执行此操作的权限!'
def has_permission(self, request, view):
"""
判断该用户有没有权限
"""
# 判断用户是不是VIP用户
# 如果是VIP用户就返回True
# 如果是普通用户就返回False
print('我要进行自定义的权限判断啦....') if request.method in ['POST', 'PUT', 'DELETE']:
print(request.user.username)
print(request.user.type)
if request.user.type == : # 是VIP用户
return True
else:
return False
else:
return True
发送正确的值
查看返回结果
查看表app01_comment记录
全局级别设置
修改settings.py,增加一行
REST_FRAMEWORK = {
# 表示app01-->utils下的auth.py里面的MyAuth类
# "DEFAULT_AUTHENTICATION_CLASSES": ["app01.utils.auth.MyAuth", ]
"DEFAULT_PERMISSION_CLASSES": ["app01.utils.permission.MyPermission", ]
}
修改views.py,注释局部的
四、DRF节流
DRF节流源码分析
请参考链接:
http://www.cnblogs.com/derek1184405959/p/8722638.html
自定义限制类
对IP做限制,60秒只能访问3次
在about_drf\app01\utils下面创建throttle.py
"""
自定义的访问限制类
"""
from rest_framework.throttling import BaseThrottle, SimpleRateThrottle
import time D = {} # {'127.0.0.1': [, ,...]} class MyThrottle(BaseThrottle): def allow_request(self, request, view):
"""
返回True就放行,返回False表示被限制了...
"""
# . 获取当前访问的IP
ip = request.META.get("REMOTE_ADDR")
print('这是自定义限制类中的allow_request')
print(ip)
# . 获取当前的时间
now = time.time()
# 判断当前ip是否有访问记录
if ip not in D:
D[ip] = [] # 初始化一个空的访问历史列表
# 高端骚操作
history = D[ip]
while history and now - history[-] > :
history.pop()
# 判断最近一分钟的访问次数是否超过了阈值(3次)
if len(history) >= :
return False
else:
# 把这一次的访问时间加到访问历史列表的第一位
D[ip].insert(, now)
return True
代码解释:
request.META.get("REMOTE_ADDR") 获取远程IP
D 存储的值,类似于
"192.168.1.2":["17:06:45","12:04:03","12:04:01"]
最后一个元素,就是最先开始的时间
for循环列表,不能对列表做更改操作!所以使用while循环
while history and now - history[-] > :
history.pop()
history是历史列表,history[-1] 表示列表最后一个元素
history and now - history[-1] > 10 表示当历史列表中有元素,并且当前时间戳减去最后一个元素的时间戳大于10的时候,执行history.pop(),表示删除最后一个元素
当历史列表为空时,或者小于差值小于10的时候,结束循环。
视图使用
修改views.py
from django.shortcuts import render, HttpResponse
from app01 import models
from app01 import app01_serializers # 导入自定义的序列化
from rest_framework.viewsets import ModelViewSet
from rest_framework.views import APIView
from rest_framework.response import Response
from app01.utils.auth import MyAuth # app01.utils.auth表示app01目录下的utils下的auth.py
from app01.utils.permission import MyPermission
from app01.utils.throttle import MyThrottle # Create your views here. # 生成Token的函数
def get_token_code(username):
"""
根据用户名和时间戳生成用户登陆成功的随机字符串
:param username: 字符串格式的用户名
:return: 字符串格式的Token
"""
import time
import hashlib
timestamp = str(time.time()) # 当前时间戳
m = hashlib.md5(bytes(username, encoding='utf8'))
m.update(bytes(timestamp, encoding='utf8')) # update必须接收一个bytes
return m.hexdigest() # 登陆视图
class LoginView(APIView):
"""
登陆检测视图
. 接收用户发过来(POST)的用户名和密码数据
. 校验用户名密码是否正确
- 成功就返回登陆成功(发Token)
- 失败就返回错误提示
""" def post(self, request): # POST请求
res = {"code": }
# 从post里面取数据
username = request.data.get("username")
password = request.data.get("password")
# 去数据库查询
user_obj = models.UserInfo.objects.filter(
username=username,
password=password,
).first()
if user_obj:
# 登陆成功
# 生成Token
token = get_token_code(username)
# 将token保存
# 用user=user_obj这个条件去Token表里查询
# 如果有记录就更新defaults里传的参数, 没有记录就用defaults里传的参数创建一条数据
models.Token.objects.update_or_create(defaults={"token": token}, user=user_obj)
# 将token返回给用户
res["token"] = token
else:
# 登录失败
res["code"] =
res["error"] = '用户名或密码错误'
return Response(res) class CommentViewSet(ModelViewSet):
queryset = models.Comment.objects.all()
serializer_class = app01_serializers.CommentSerializer
authentication_classes = [MyAuth, ] # 局部使用认证方法MyAuth
# permission_classes = [MyPermission, ] # 局部使用权限方法
throttle_classes = [MyThrottle, ] # 局部使用限制方法
使用postman发送GET请求
疯狂的点击SEND按钮,多发送几次
提示请求达到了限制
等待十几秒,就可以访问了
全局使用
修改settings.py
REST_FRAMEWORK = {
# 表示app01-->utils下的auth.py里面的MyAuth类
# "DEFAULT_AUTHENTICATION_CLASSES": ["app01.utils.auth.MyAuth", ],
#"DEFAULT_PERMISSION_CLASSES": ["app01.utils.permission.MyPermission", ],
"DEFAULT_THROTTLE_CLASSES": ["app01.utils.throttle.MyThrottle", ]
}
修改views.py,注释掉代码
使用内置限制类
修改about_drf\app01\utils\throttle.py
"""
自定义的访问限制类
"""
from rest_framework.throttling import BaseThrottle, SimpleRateThrottle
# import time
#
# D = {} # {'127.0.0.1': [, ,...]}
#
#
# class MyThrottle(BaseThrottle):
#
# def allow_request(self, request, view):
#
# """
# 返回True就放行,返回False表示被限制了...
# """
# # . 获取当前访问的IP
# ip = request.META.get("REMOTE_ADDR")
# print('这是自定义限制类中的allow_request')
# print(ip)
# # . 获取当前的时间
# now = time.time()
# # 判断当前ip是否有访问记录
# if ip not in D:
# D[ip] = [] # 初始化一个空的访问历史列表
# # 高端骚操作
# history = D[ip]
# while history and now - history[-] > :
# history.pop()
# # 判断最近一分钟的访问次数是否超过了阈值(3次)
# if len(history) >= :
# return False
# else:
# # 把这一次的访问时间加到访问历史列表的第一位
# D[ip].insert(, now)
# return True class MyThrottle(SimpleRateThrottle): scope = "rate" # rate是名字,可以随便定义! def get_cache_key(self, request, view):
return self.get_ident(request)
注意:scope是关键字参数
get_cache_key 的名字不能变动
self.get_ident(request) 表示远程IP地址
全局配置
REST_FRAMEWORK = {
# 表示app01-->utils下的auth.py里面的MyAuth类
# "DEFAULT_AUTHENTICATION_CLASSES": ["app01.utils.auth.MyAuth", ]
"DEFAULT_PERMISSION_CLASSES": ["app01.utils.permission.MyPermission", ],
"DEFAULT_THROTTLE_CLASSES": ["app01.utils.throttle.MyThrottle", ],
"DEFAULT_THROTTLE_RATES": {
"rate": "3/m",
}
}
注意:rate对应的是throttle.py里面MyThrottle定义的scope属性的值
3/m 表示1分钟3次
再次测试,效果如下:
它还会返回倒计时的时间!
(四) DRF认证, 权限, 节流的更多相关文章
- drf(请求封装/认证/权限/节流)
1.请求的封装 class HttpRequest(object): def __init__(self): pass @propery def GET(self): pass @propery de ...
- drf认证、节流、权限、版本
Django rest framework 认证: 作用:验证用户是否登录 在视图类中写上authentication_classes = [ ],这是一个列表 需要实现 authenticate() ...
- 三 drf 认证,权限,限流,过滤,排序,分页,异常处理,接口文档,集xadmin的使用
因为接下来的功能中需要使用到登陆功能,所以我们使用django内置admin站点并创建一个管理员. python manage.py createsuperuser 创建管理员以后,访问admin站点 ...
- DRF 认证 权限 视图 频率
认证组件 使用:写一个认证类,继承BaseAuthentication 在类中写authenticate方法,把request对象传入 能从request对象中取出用户携带的token根据token判 ...
- python 全栈开发,Day97(Token 认证的来龙去脉,DRF认证,DRF权限,DRF节流)
昨日内容回顾 1. 五个葫芦娃和三行代码 APIView(views.View) 1. 封装了Django的request - request.query_params --> 取URL中的参数 ...
- drf认证组件、权限组件、jwt认证、签发、jwt框架使用
目录 一.注册接口 urls.py views.py serializers.py 二.登录接口 三.用户中心接口(权限校验) urls.py views.py serializers.py 四.图书 ...
- drf认证组件(介绍)、权限组件(介绍)、jwt认证、签发、jwt框架使用
目录 一.注册接口 urls.py views.py serializers.py 二.登录接口 三.用户中心接口(权限校验) urls.py views.py serializers.py 四.图书 ...
- DRF 认证、权限、限制
DRF 认证.权限.限制 认证: 定义一个用户表和一个保存用户的Token表 # ======================day96======================= class ...
- DRF之权限认证频率组件
概要 retrieve方法源码剖析 认证组件的使用方式及源码剖析 权限组件的使用方式及源码剖析 频率组件的使用方式及源码剖析 知识点复习回顾 Python逻辑运算 知识点复习回顾一:Python逻辑运 ...
随机推荐
- hadoop的checkpoint检查时间参数设置
1.通常情况下,SecondaryNameNode 每隔一小时执行一次. 在hdfs-default.xml文件中: <property> <name>dfs.namenode ...
- python-备忘录模式
源码地址:https://github.com/weilanhanf/PythonDesignPatterns 说明: 一个成熟的软件应当允许用户取消不确定的操作或者从错误的状态中恢复过来.复制,粘体 ...
- js-ES6学习笔记-Class(6)
1.类相当于实例的原型,所有在类中定义的方法,都会被实例继承.如果在一个方法前,加上static关键字,就表示该方法不会被实例继承,而是直接通过类来调用,这就称为“静态方法”. 2.父类的静态方法,可 ...
- 如何将在线电子书保存为pdf格式
网上有很多免费的在线电子书籍,没有pdf格式,不方便离线阅读,也不方便做记录,所以找了几个将在线内容制作成pdf文件的方法. 一.如果网站上的书籍内容没有分页,所有内容都直接显示出来了,最简单,直接将 ...
- 【转】boost库之geometry
#include <boost/assign.hpp> #include <boost/geometry/geometry.hpp> #include <boost/ge ...
- 浅尝Java(一)
主题:数据类型,数值类型变量相互转化 Java是强类型的语言,与JavaScript(松散型)在数据类型上有很大的差异(1.所有变量必须先申明,后使用:2.指定类型的变量只接受与之匹配类型的值).这个 ...
- tomcat报错this web application instance has been stopped already问题
上网搜了下,大部分的报错原因:重启时候 之前的tomcat未正常关闭 ,导致在重启时候 报了这个问题.mac下解决: ps -ef|grep tomcat 找到在进行的tomcat ,kill -9 ...
- API接口安全设计(转)
接口的安全性主要围绕Token.Timestamp和Sign三个机制展开设计,保证接口的数据不会被篡改和重复调用,下面具体来看: Token授权机制:用户使用用户名密码登录后服务器给客户端返回一个To ...
- 转:SqlServer索引及优化详解
(一)深入浅出理解索引结构 实际上,您可以把索引理解为一种特殊的目录.微软的SQL SERVER提供了两种索引:聚集索引(clustered index,也称聚类索引.簇集索引)和非聚集索引(nonc ...
- Google搜索引擎
一.基本搜索 逻辑符 与(空格).或(OR).非(-). ""全匹配搜索 加入双引号表示完全匹配搜索 *通配符 二.高级搜索 intitle:只搜索网页标题(即html的title ...