Good idea to use REST token authentication for AJA

2019-05-28 18:06发布

问题:

I created a REST web API using Python/Django and the excellent Django REST Framework.

I'm experimenting with authentication methods at the moment and was wondering if it's a good practice to use "token authentication" for AJAX web apps.

I included a sample HTML file with a very basic CRUD web app, demonstrating how I'm using token authentication at the moment. It works fine, but is it really OK (regarding security and so) to just include the authentication token in the source? Basic authentication seems like a good alternative, but then I would have to include both the username AND password in the source, which seems even worse to me?

Footnote: I know REST is better used through the HTTPS protocol for security, but I'm running this code on my development machine, obviously. I'm planning on using HTTPS in production.

Thanks in advance for any tips!

Kind regards, Kristof

{% extends 'base.html' %}
{% block title %}Games{% endblock %}
{% block content %}<script type="text/javascript">/*<![CDATA[*/
function getBase() {
    return 'http://api.sandbox.dev:8080/';
}
function getData() {
    return {
        id: $('#id').val(),
        title: $('#title').val(),
    };
}
function getToken() {
    return 'b26ffd6ddb66428ce9164d606f694cd4184ce73e';
}
$(document).ready(function(){
    $('#create').click(function(e){
        $.ajax({
            url: getBase() + 'games/',
            type: 'POST',
            data: getData(),
            dataType: 'json',
            headers: {
                authorization: 'token ' + getToken(),
            },
            complete: function(xhr, textStatus) {
                console.log('textStatus = ' + textStatus);
            },
            success: function(data, textStatus, xhr) {
                console.log('textStatus = ' + textStatus);
            },
            error: function(xhr, textStatus, errorThrown) {
                console.log('textStatus = ' + textStatus + '\nerrorThrown = ' + errorThrown);
            },
        });
    });
    $('#update').click(function(e){
        if(getData().id) {
            $.ajax({
                url: getBase() + 'games/' + getData().id + '/',
                type: 'PUT',
                data: getData(),
                dataType: 'json',
                headers: {
                    authorization: 'token ' + getToken(),
                },
                complete: function(xhr, textStatus) {
                    console.log('textStatus = ' + textStatus);
                },
                success: function(data, textStatus, xhr) {
                    console.log('textStatus = ' + textStatus);
                },
                error: function(xhr, textStatus, errorThrown) {
                    console.log('textStatus = ' + textStatus + '\nerrorThrown = ' + errorThrown);
                },
            });
        }
    });
    $('#delete').click(function(e){
        if(getData().id) {
            $.ajax({
                url: getBase() + 'games/' + getData().id + '/',
                type: 'DELETE',
                data: {},
                dataType: 'json',
                headers: {
                    authorization: 'token ' + getToken(),
                },
                complete: function(xhr, textStatus) {
                    console.log('textStatus = ' + textStatus);
                },
                success: function(data, textStatus, xhr) {
                    console.log('textStatus = ' + textStatus);
                },
                error: function(xhr, textStatus, errorThrown) {
                    console.log('textStatus = ' + textStatus + '\nerrorThrown = ' + errorThrown);
                },
            });
        }
    });
});
/*]]>*/</script><form action="" method="post" onsubmit="return false">
    <dl>
        <dt><label for="id">ID</label></dt>
        <dd><input type="text" id="id" name="id" size="20" maxlength="10" /></dd>
        <dt><label for="title">Title</label></dt>
        <dd><input type="text" id="title" name="title" size="20" maxlength="20" /></dd>
    </dl>
    <p><button type="button" id="create">Create</button></p>
    <p><button type="button" id="update">Update</button></p>
    <p><button type="button" id="delete">Delete </button></p>
</form>{% endblock %}

回答1:

TokenAuthentication is mostly used with native clients connecting to server, things like iOS, Android or windows apps etc..

When dealing with ajax (using web app), you should use SessionAuthentication. This saves you from providing any additional data. The only requirement is for user to be logged in.



回答2:

TokenAuthentication and SessionAuthentication behavior is similar when you look at the HTTP telegrams: both of them are sending in plain text the username and password during login and afterwards they mark their requests with a hash uniquely identifying them to the system (token uses the headers, sessions are persisted on server-side cookies).

One has to understand that session authentication keeps the sessions in the dB back-end, which do requires maintenance in a production system (who cleans up the expired sessions ?), or it may be a performance bottleneck, demanding cache-based solutions.

I would choose SessionAuthentication only if I would need to implement some kind of timeout mechanism, so that I would render sessions as expired after let's say 15 minutes of inactivity, or to inspect if an user has multiple logins (from several browsers which most likely resides in several machines).

Bottom line: you are perfectly fine with TokenAuthentication, if you go with SessionAuthentication care that it will truly serve your purpose, otherwise it brings some issues to deal with not so obvious.