如何在Django中通过AJAX设置令牌认证以保护API URL

时间:2017-05-06 19:25:02

标签: ajax django django-rest-framework token django-authentication

我正在使用Django REST框架在JSON中提供数据并使用它们通过AJAX刷新页面。如何保护页面正在使用数据更新的URL,并且没有人可以访问API URL。该URL在AJAX中以html显示,因此可以访问它,但我想通过令牌或任何其他适当的身份验证来阻止它只访问它有网站。

网址为'/ api / item /'(参见AJAX代码)

serializers.py

from rest_framework import serializers

from .models import Item

class ItemModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = Item
        fields = [
            'title',
            'value',
        ]

views.py(在API中)

from rest_framework import generics
from .serializers import ItemModelSerializer
from .models import Item

class ItemListAPIView(generics.ListAPIView):
    serializer_class = ItemModelSerializer

    def get_queryset(self):
        return Item.objects.all().order_by('sort')

urls.py

urlpatterns = [
    #...urls...
    url(r'^api/item/', include('apps.item.api.urls', namespace='api-item')),
    url(r'^admin/', admin.site.urls),
]

模板 - ajax

setInterval(function() {
    $.ajax({
        method: "GET",
        url: "/api/item/",
        success: function(data) {
            $("#items tbody").empty();
            $.each(data, function (key, value) {                                      
                var itemKey = key;
                var itemTitle = value.title;  
                var itemValue = value.value;
                $("#items tbody").append(
                   "<tr><td class='left'>" + itemTitle + "</td><td>" + itemValue</td></tr>"
                )
            })
        },
        error: function(data) {
            console.log("error")
            console.log(data)
        }
    })
}, 3000)

2 个答案:

答案 0 :(得分:0)

我不确定我是否正确理解了你的问题,我猜你是在问你如何在Django中为你的API设置AJAX中的令牌。通常,我们使用共享令牌的概念。将有一个登录API,用于使用用户名/密码对用户进行身份验证。如果凭据正确,auth API将返回您可以使用的令牌并在AJAX请求中设置。使用该令牌进一步调用API进行身份验证。

如果您直接想要在没有auth API的情况下调用API,则必须使用Django和AJAX之间共享的硬编码令牌,但遵循此类做法是不安全的。

在此处查看DRF身份验证http://www.django-rest-framework.org/api-guide/authentication/#sessionauthentication

答案 1 :(得分:0)

我做了类似的事情:

@Shwetabh Sharan,您将不得不使用在Django和AJAX之间共享的硬编码令牌

但是

@Shwetabh Sharan说,但是,遵循这种做法是不安全的

到目前为止,没有人解决过如何在Django,AJAX和JS中确保GET或POST请求的安全的问题,只有该网站可以使用它,其他人都无法使用

他们总是建议使用“ JWT,令牌身份验证和会话身份验证”等。但是所有这些解决方案都需要用户注册,如果我想保护搜索自动完成字段或前端的任何公共内容,会发生什么情况

我创建了一个rest框架自定义权限,并且使用了django csrfmiddlewaretoken

它的行为与Django帖子形式相同,csrf令牌中间件发送用{% csrf_token %}隐藏的输入类型(用令牌隐藏的输入),但是这种情况下只需要{{ csrf_token }}(令牌),Django将请求令牌与已加密的Cookie令牌进行比较

permission.py
    from django.middleware.csrf import _compare_salted_tokens, rotate_token
    from rest_framework.permissions import BasePermission


    class HasCsrfTokenValid(BasePermission):
        def has_permission(self, request, view):
            token_valid = False
            try:
                csrf_token = request.headers.get("api-csrftoken")
                csrf_cookie = request.META.get("CSRF_COOKIE")

                """
                Check if both alphanumerics(strings) values are differents to prevent 
                a malicious user get the csrf cookie and send it from the ajax.
                """
                if csrf_token == csrf_cookie:
                    rotate_token(request)
                    return False

                token_valid =  _compare_salted_tokens(csrf_token, csrf_cookie)
            except ValueError: # if csrf_token & csrf_cookie are not a valid alphanumeric
                return False
            return token_valid

将权限类添加到api视图

views.py
class SnippetSearchAPI(generics.ListAPIView):
    model = Snippet
    serializer_class = SnippetSearcSerializer
    permission_classes = [HasCsrfTokenValid,]
    queryset = Snippet.objects.all()

Ajax请求:

$('#search-snippet').keyup(function () {
    $.ajax({
       url:"{% url 'snippet-search-space:api' %}",
       headers:{'api-csrftoken':'{{ csrf_token }}'},
       success:function(data){
         console.log(data)
       }
   });
 });