Compiling RESTful APIs in Django (4): authentication and permissions, djangorestful

Source: Internet
Author: User
Tags lexer

Compiling RESTful APIs in Django (4): authentication and permissions, djangorestful

Welcome to my personal website: www.comingnext.cn

Preface:

As described in the previous articles, the basic functions of using Django to write RESTful APIs are already decent. We can access different resources through different URLs and perform different operations on resources through different HTTP requests.

However, our API also has an obvious defect: There is no authentication and permission function, and any resource will be changed by any user. Therefore, we need to improve the program to implement the following functions:

Modify snippet Model

First, we want to associate snippets with their creation users. Therefore, we naturally need to add an owner field in the Snippet model for representation. In addition, we add a highlighted field to highlight the code and modify Snippet of snippets/models. py:

owner = models.ForeignKey('auth.User', related_name='snippets', on_delete=models.CASCADE)highlighted = models.TextField()

 

To achieve code highlighting, of course, this is not the case with the previous line of code. It is still a common field. What we need to do is to use pygments to generate the highlighted HTML when saving () is executed, or in model. py, first import the relevant Library:

from pygments.lexers import get_lexer_by_namefrom pygments.formatters.html import HtmlFormatterfrom pygments import highlight

 

Then add the save () method to the Snippet class:

Def save (self, * args, ** kwargs): "Use the pygments library to generate HTML code that highlights the code" lexer = get_lexer_by_name (self. language) linios = self. linios and 'table' or False options = self. title and {'title': self. title} or {} formatter = HtmlFormatter (style = self. style, linios = linios, full = True, ** options) self. highlighted = highlight (self. code, lexer, formatter) super (Snippet, self ). save (* args, ** kwargs)

 

When saving data, the above method is executed. The function of the entire method is shown in a comment. This function is not displayed in this article, it will be shown in the following article.

If you modify the model, you must synchronize the database. Here, we delete the database in the same way as the official document and re-generate the database. First, we will delete the database in the project directory. delete the migrations folder under sqlite3 and snippets, and then perform the migration steps:

python manage.py makemigrations snippetspython manage.py migrate

 

At the same time, because we want to display the corresponding creators when accessing Each snippet, we need to create several different accounts to display them later.

python manage.py createsuperuser

 

Add endpoints for our user model

The principle is basically the same as the previous SnippetSerializer. Add a User serializer in snippets/serializers. py:

from django.contrib.auth.models import Userclass UserSerializer(serializers.ModelSerializer):    snippets = serializers.PrimaryKeyRelatedField(many=True, queryset=Snippet.objects.all())    class Meta:        model = User        fields = ('id', 'username', 'snippets')

 

Note the following:

snippets = serializers.PrimaryKeyRelatedField(many=True, queryset=Snippet.objects.all())

 

Because snippets is a inverse relation in the User model, the relationship is not included by default when ModelSerializer class is used, that is, the User can be queried through the Snippet owner, the User side cannot find a snippet created by the User, so we need to manually add this field for the User sequence.

After the User serializer is ready, it is necessary to display it. Therefore, you need to add the relevant view class and edit view. py:

from django.contrib.auth.models import Userfrom snippets.serializers import UserSerializerclass UserList(generics.ListAPIView):    queryset = User.objects.all()    serializer_class = UserSerializerclass UserDetail(generics.RetrieveAPIView):    queryset = User.objects.all()    serializer_class = UserSerializer

 

After writing the view functions and accessing them through urls, you must configure route distribution, edit snippets/urls. py, and add the following matching mode:

url(r'^users/$', views.UserList.as_view()),url(r'^users/(?P<pk>[0-9]+)/$', views.UserDetail.as_view()),

 

Associate Snippets with Users

At this point, we cannot associate Snippets with Users if we create code segments as before. This is because User data is transmitted through request instead of serialized data.

We just added an owner as the foreign key, so we will see its usefulness. Edit view. py and add a method for the SnippetList view class:

class SnippetList(generics.ListCreateAPIView):    queryset = Snippet.objects.all()    serializer_class = SnippetSerializer    permission_classes = (permissions.IsAuthenticatedOrReadOnly,)    def perform_create(self, serializer):        serializer.save(owner=self.request.user)

 

This parameter m_create () allows you to assign the user in the request to the Snippet owner when creating a new Snippet through the POST request and saving the new Snippet data. You can easily understand it when using it.

Update serializer

The two are associated in the previous step. The owner will have all attributes of the User when creating a new Snippet. In this case, the owner must display the id or User name in the API to improve readability, the answer is to display the user name, so we add a field under SnippetSerializer:

owner = serializers.ReadOnlyField(source='owner.username')

 

The source parameter specifies the attribute used to fill the field. To display the owner when using the field, but add it to the Meta class, the entire SnippetSerializer is as follows:
Class SnippetSerializer (serializers. modelSerializer): # Here you can use CharField (read_only = True) to replace owner = serializers. readOnlyField (source = 'owner. username') class Meta: model = Snippet fields = ('id', 'title', 'code', 'linano', 'language', 'style', 'owner ')

 

Add permission

Now, Snippet and User are associated and browsed. Next we need to implement timely permissions. That is, in the first few points we mentioned:

First, import a library in views. py:

from rest_framework import permissions

 

Next, add the permission judgment for SnippetList and SnippetDetail, and add them to both view classes:

permission_classes = (permissions.IsAuthenticatedOrReadOnly,)

Note that the comma must be added, or an error will be reported.

This line of code is used to determine whether the current user is the creator of the Snippet, while other users only have read-only attributes, that is, they can only view.

 

Add a logon function for a browsed API

I added the permission judgment just now. If you have not logged on to a user, it is equivalent to a visitor. You can only view all functions. Therefore, You need to log on to the API in your browser. Here, the powerful django-rest-framework has done a lot for us. To add the login button and page, you only need to modify a rest_tutorial/urls. py to add a URL match:

urlpatterns += [    url(r'^api-auth/', include('rest_framework.urls',                               namespace='rest_framework')),]

 

Here, you can set R' ^ api-auth/'to whatever you like, but the namespace must be the same, that is, namespace = 'rest _ framework '.

Now, open your browser and you will see a login button in the upper-right corner of our API page. Click it to log on to the user you created.

When you access the details of a single user, you can see the id values of all Snippet created by the user (you need to create several Snippet first, you can follow the method in shell mode in the first article in this series ). For example, access:

http://127.0.0.1:8000/users/2/

 

You can see:

Add object permissions

What we need to achieve is that all snippets can be accessed by everyone, but only the creator of Each Snippet can modify or delete it.

Therefore, we need to set custom permissions so that each Snippet can only be edited by its creator. Create a new permissions. py in the snippets directory:

From rest_framework import permissionsclass IsOwnerOrReadOnly (permissions. basePermission): "enables each Snippet to only allow its creator to edit it" def has_object_permission (self, request, view, obj ): # Any user or visitor can access any Snippet, so when the request action is within the security scope, # That is, when the GET, HEAD, and OPTIONS requests are received, the if request is allowed. method in permissions. SAFE_METHODS: return True # when the request is not in the above security mode, you need to determine the current user # If the Snippet owner is consistent with the current user, then allow, otherwise, return obj. owner = request. user

 

The Code logic is already being commented. Simply put, it provides the judgment function. Then we need to apply it and modify the SnippetDetail in view. py:

class SnippetDetail(generics.RetrieveUpdateDestroyAPIView):    queryset = Snippet.objects.all()    serializer_class = SnippetSerializer    permission_classes = (permissions.IsAuthenticatedOrReadOnly,                          IsOwnerOrReadOnly,)

 

Note: to import the IsOwnerOrReadOnly class:

from snippets.permissions import IsOwnerOrReadOnly

 

Open a single Snippet details page in a browser. If the user you are currently logged on to is the creator of the Snippet, you will find two more operations, DELETE and PUT, such as accessing http: // 127.0.0.1: 8000/snippets/2/. The effect is as follows:

Use API authorization

Because the authentication class is not used yet, the default SessionAuthentication and BasicAuthentication are used for the project.

When you use a browser to access the API, the browser will save the session information. Therefore, you can delete or change an Snippet when the permission is satisfied, or create a new Snippet.

If you use the command line to operate the API, you must add the authorization information, namely the user name and password, each time you send a request. If not, an error is reported, for example:

http POST http://127.0.0.1:8000/snippets/ code="print 123"{    "detail": "Authentication credentials were not provided."}

 

The correct operation is as follows:

http -a username1:password POST http://127.0.0.1:8000/snippets/ code="print 789"{    "id": 1,    "owner": "username1",    "title": "",    "code": "print 789",    "linenos": false,    "language": "python",    "style": "friendly"}

 

We can see that the owner is the submitted user name, which is the embodiment of the code above:

    def perform_create(self, serializer):        serializer.save(owner=self.request.user)

 

The owner can better understand the program in actual use. This is what the owner obtains when a user creates an Snippet.

The authentication and permissions are obtained first. In the code we wrote above, in the highlight section, we say that its function is to generate HTML code that can highlight the code segment. This part is not used yet. Next we will introduce it.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.