How to add change password functionality to Django / React app

可紊 提交于 2021-01-28 02:06:47

问题


I'm trying to add change password functionality to a Django / React app. I'm struggling to find any way to make this work. I'm using django-rest-auth and django-rest-framework.

I would be happy to either submit the password change request from a React page, or else to redirect the user to the native Django template-driven page - leaving my SPA, but acceptable to get the functionality working.

However, the change password page requires the user to be logged in, and I can't see how to do this from the React app. I've set up the Django page with a custom template, but if I link to it from the app then the URL redirects to login:

If I copy the request to cURL and run it in a terminal, I see this error:

# api/urls.py
from django.urls import include, path
from django.contrib.auth import views
from django.conf.urls import include, url

urlpatterns = [
...
    path('password_change/', views.PasswordChangeView.as_view(template_name='account/password_change.html'), name='password_change'),
]

account/password_change.html

{% extends 'account/base.html' %}

{% block body_block %}
  <h1>Change your password</h1>
  <form method="post" action=".">
    {% csrf_token %}
    {{ form.as_p }}
    <input type="submit" value="Submit" />
  </form>
{% endblock %}

I log in to my app and then navigate to where the change password page should be:

http://localhost:8000/api/v1/password_change/

This is then redirected to:

http://localhost:8000/accounts/login/?next=/api/v1/password_change/

My guess is that this is because the endpoint requires authentication and it's not been provided. But although I have a stored authentication token, I can't find out how to send this as part of the weblink and previous experience with reset password suggests that it's not the token Django would be looking for from a template.

I've hunted for ages and can't find any example of how to add change password to a React app. Surely this must be something every React app needs? What basic thing am I missing?

Edit: thanks to Rik Schoonbeek for the answer, which is that the endpoint supplied by djang-rest-auth can be used directly. Somehow I missed this in all my confusion. In case it helps anybody else, here is sample working code that uses JavaScript fetch and hard-coded passwords instead of data from the form, just to demonstrate the process.

This code also demonstrates detecting an error in the fetch command, which doesn't work quite like you might expect. There are probably better ways to do it, but this does at least give you a hook.

Working code:

export const changePassword = () => (dispatch) => {
    const token = localStorage.getItem('jwtToken');

    const data = {
        'new_password1': 'othertext',
        'new_password2': 'othertext',
        'old_password': 'sometext'
    };

    var formData  = new FormData();

    // Push our data into our FormData object
    for(var name in data) {
        formData.append(name, data[name]);
    }

    const headers = {
        'Authorization': `Token ${token}`,
    };

    return fetch('/api/v1/rest-auth/password/change/', {
        headers,
        'method': 'POST',
        'body': formData,
    })
        .then(res => {
            if(res.ok) {
                console.log('successfully changed password');
                return res.json();
            } else {
                console.log('error changing password');
            }
        })
        .then(res => {
            console.log('Change password res ', res);
        });
};

And important! add this to settings.py, otherwise the password will be changed regardless of whether the old password is correct:

OLD_PASSWORD_FIELD_ENABLED = True

And if you want the user to stay logged in after they have reset their password, add this too:

LOGOUT_ON_PASSWORD_CHANGE = False

回答1:


If you use token authentication, like I do, you can authorize the user by sending the token in the header of the request to change the password. You need to add "Token " in front of the token though (see example below).

This is how I did it, using axios, and token authentication.

const response = await axios.post(
  "http://127.0.0.1:8000/rest-auth/password/change/",
  values,
  {
    headers: { Authorization: "Token " + this.props.loginToken }
  }
);

The password change endpoint requires the following data to be sent:

  • new_password1
  • new_password2
  • old_password

As explained here in the django-rest-auth docs

So, the "values" parameter in my above axios request is a json containing those values.



来源:https://stackoverflow.com/questions/54055768/how-to-add-change-password-functionality-to-django-react-app

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!