fix merge issue

This commit is contained in:
Steve Recio 2020-06-02 21:02:44 -04:00
commit c03558bd2f
103 changed files with 1687 additions and 609 deletions

34
.circleci/config.yml Normal file
View File

@ -0,0 +1,34 @@
version: 2.1
orbs:
docker: circleci/docker@0.6.0
jobs:
test-django-3: &template
docker:
- image: circleci/python:3.8.0
environment:
DJANGO_VERSION: 3.0.3
DRF: 3.11
executor: docker/docker
steps:
- checkout
- run: pip install --user -r dev-requirements.txt
- run: pip install --user -r dj_rest_auth/tests/requirements.pip
- run: pip install -q --user coveralls djangorestframework==$DRF Django==$DJANGO_VERSION
- run:
command: coverage run --source=dj_rest_auth setup.py test
name: Test
- run:
command: COVERALLS_REPO_TOKEN=Q58WdUuZOi89XHyDeDsGE2lxUGQ2IfqP3 coveralls
name: Coverage
test-django-2:
<<: *template
environment:
DJANGO_VERSION: 2.2.10
DRF: 3.9
workflows:
main:
jobs:
- test-django-3
- test-django-2

2
.coveralls.yml Normal file
View File

@ -0,0 +1,2 @@
service_name: travis-pro
repo_token: Q58WdUuZOi89XHyDeDsGE2lxUGQ2IfqP3

5
.gitignore vendored
View File

@ -72,6 +72,9 @@ target/
# Jupyter Notebook
.ipynb_checkpoints
# IDE
.idea
# pyenv
.python-version
@ -102,3 +105,5 @@ venv.bak/
# mypy
.mypy_cache/
demo/react-spa/node_modules/
demo/react-spa/yarn.lock

View File

@ -1,26 +0,0 @@
language: python
python:
- "2.7"
- "3.5"
- "3.6"
env:
- DJANGO=1.11.* DRF=3.7.*
- DJANGO=1.11.* DRF=3.8.*
- DJANGO=2.0.* DRF=3.7.*
- DJANGO=2.0.* DRF=3.8.*
install:
- pip install -q Django==$DJANGO djangorestframework==$DRF
- pip install coveralls
- pip install -r rest_auth/tests/requirements.pip
script:
- coverage run --source=rest_auth setup.py test
after_success:
- coveralls
before_script:
- flake8 . --config=flake8
matrix:
exclude:
- python: "2.7"
env: DJANGO=2.0.* DRF=3.7.*
- python: "2.7"
env: DJANGO=2.0.* DRF=3.8.*

View File

@ -1 +1 @@
http://github.com/Tivix/django-rest-auth/contributors
http://github.com/jazzband/dj-rest-auth/contributors

3
CONTRIBUTING.md Normal file
View File

@ -0,0 +1,3 @@
[![Jazzband](https://jazzband.co/static/img/jazzband.svg)](https://jazzband.co/)
This is a [Jazzband](https://jazzband.co/) project. By contributing you agree to abide by the [Contributor Code of Conduct](https://jazzband.co/about/conduct) and follow the [guidelines](https://jazzband.co/about/guidelines).

View File

@ -1,6 +1,6 @@
The MIT License (MIT)
Copyright (c) 2014 Tivix
Copyright (c) 2014 iMerica https://github.com/iMerica/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@ -18,4 +18,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
SOFTWARE.

View File

@ -2,4 +2,4 @@ include AUTHORS
include LICENSE
include MANIFEST.in
include README.md
graft rest_auth
graft dj_rest_auth

77
README.md Normal file
View File

@ -0,0 +1,77 @@
# Dj-Rest-Auth
[![<iMerica>](https://circleci.com/gh/jazzband/dj-rest-auth.svg?style=svg)](https://app.circleci.com/pipelines/github/jazzband/dj-rest-auth)
[![Jazzband](https://jazzband.co/static/img/badge.svg)](https://jazzband.co/)
[![Coverage Status](https://coveralls.io/repos/github/jazzband/dj-rest-auth/badge.svg?branch=master)](https://coveralls.io/github/jazzband/dj-rest-auth?branch=master)
Drop-in API endpoints for handling authentication securely in Django Rest Framework. Works especially well
with SPAs (e.g React, Vue, Angular), and Mobile applications.
## Requirements
- Django 2 or 3.
- Python 3
## Quick Setup
Install package
pip install dj-rest-auth
Add `dj_rest_auth` app to INSTALLED_APPS in your django settings.py:
```python
INSTALLED_APPS = (
...,
'rest_framework',
'rest_framework.authtoken',
...,
'dj_rest_auth'
)
```
Add URL patterns
```python
urlpatterns = [
url(r'^dj-rest-auth/', include('dj_rest_auth.urls'))
]
```
(Optional) Use Http-Only cookies
```python
REST_USE_JWT = True
JWT_AUTH_COOKIE = 'jwt-auth'
```
### Testing
To run the tests within a virtualenv, run `python runtests.py` from the repository directory.
The easiest way to run test coverage is with [`coverage`](https://pypi.org/project/coverage/),
which runs the tests against all supported Django installs. To run the test coverage
within a virtualenv, run `coverage run ./runtests.py` from the repository directory then run `coverage report`.
#### Tox
Testing may also be done using [`tox`](https://pypi.org/project/tox/), which
will run the tests against all supported combinations of python and django.
Install tox, either globally or within a virtualenv, and then simply run `tox`
from the repository directory. As there are many combinations, you may run them
in [`parallel`](https://tox.readthedocs.io/en/latest/config.html#cmdoption-tox-p)
using `tox --parallel`.
The `tox.ini` includes an environment for testing code [`coverage`](https://pypi.org/project/coverage/)
and you can run it and view this report with `tox -e coverage`.
Linting may also be performed via [`flake8`](https://pypi.org/project/flake8/)
by running `tox -e flake8`.
### Documentation
View the full documentation here: https://dj-rest-auth.readthedocs.io/en/latest/index.html
### Acknowledgements
This project began as a fork of `django-rest-auth`. Big thanks to everyone who contributed to that repo!

View File

@ -1,31 +0,0 @@
Welcome to django-rest-auth
===========================
.. image:: https://travis-ci.org/Tivix/django-rest-auth.svg
:target: https://travis-ci.org/Tivix/django-rest-auth
.. image:: https://coveralls.io/repos/Tivix/django-rest-auth/badge.svg
:target: https://coveralls.io/r/Tivix/django-rest-auth?branch=master
.. image:: https://readthedocs.org/projects/django-rest-auth/badge/?version=latest
:target: https://readthedocs.org/projects/django-rest-auth/?badge=latest
Django-rest-auth provides a set of REST API endpoints for Authentication and Registration
Documentation
-------------
http://django-rest-auth.readthedocs.org/en/latest/
Source code
-----------
https://github.com/Tivix/django-rest-auth
Stack Overflow
-----------
http://stackoverflow.com/questions/tagged/django-rest-auth

View File

@ -31,23 +31,23 @@ INSTALLED_APPS = (
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
# 'django.contrib.messages',
'django.contrib.messages',
'django.contrib.staticfiles',
'django.contrib.sites',
'rest_framework',
'rest_framework.authtoken',
'rest_auth',
'dj_rest_auth',
'allauth',
'allauth.account',
'rest_auth.registration',
'dj_rest_auth.registration',
'allauth.socialaccount',
'allauth.socialaccount.providers.facebook',
'rest_framework_swagger',
'corsheaders'
)
MIDDLEWARE = (
'corsheaders.middleware.CorsMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
@ -116,14 +116,23 @@ ACCOUNT_EMAIL_REQUIRED = False
ACCOUNT_AUTHENTICATION_METHOD = 'username'
ACCOUNT_EMAIL_VERIFICATION = 'optional'
REST_USE_JWT = True
JWT_AUTH_COOKIE = 'auth'
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.SessionAuthentication',
'rest_framework.authentication.TokenAuthentication',
)
'dj_rest_auth.utils.JWTCookieAuthentication'
),
'DEFAULT_SCHEMA_CLASS': 'rest_framework.schemas.coreapi.AutoSchema'
}
SWAGGER_SETTINGS = {
'LOGIN_URL': 'login',
'LOGOUT_URL': 'logout',
}
# For demo purposes only. Use a white list in the real world.
CORS_ORIGIN_ALLOW_ALL = True

View File

@ -1,7 +1,6 @@
from django.conf.urls import include, url
from django.contrib import admin
from django.views.generic import TemplateView, RedirectView
from django.views.generic import RedirectView, TemplateView
from rest_framework_swagger.views import get_swagger_view
urlpatterns = [
@ -35,8 +34,8 @@ urlpatterns = [
TemplateView.as_view(template_name="password_reset_confirm.html"),
name='password_reset_confirm'),
url(r'^rest-auth/', include('rest_auth.urls')),
url(r'^rest-auth/registration/', include('rest_auth.registration.urls')),
url(r'^dj-rest-auth/', include('dj_rest_auth.urls')),
url(r'^dj-rest-auth/registration/', include('dj_rest_auth.registration.urls')),
url(r'^account/', include('allauth.urls')),
url(r'^admin/', admin.site.urls),
url(r'^accounts/profile/$', RedirectView.as_view(url='/', permanent=True), name='profile-redirect'),

View File

@ -8,7 +8,9 @@ https://docs.djangoproject.com/en/1.7/howto/deployment/wsgi/
"""
import os
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "demo.settings")
from django.core.wsgi import get_wsgi_application
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "demo.settings")
application = get_wsgi_application()

23
demo/react-spa/.gitignore vendored Normal file
View File

@ -0,0 +1,23 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.js
# testing
/coverage
# production
/build
# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local
npm-debug.log*
yarn-debug.log*
yarn-error.log*

68
demo/react-spa/README.md Normal file
View File

@ -0,0 +1,68 @@
This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).
## Available Scripts
In the project directory, you can run:
### `yarn start`
Runs the app in the development mode.<br />
Open [http://localhost:3000](http://localhost:3000) to view it in the browser.
The page will reload if you make edits.<br />
You will also see any lint errors in the console.
### `yarn test`
Launches the test runner in the interactive watch mode.<br />
See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information.
### `yarn build`
Builds the app for production to the `build` folder.<br />
It correctly bundles React in production mode and optimizes the build for the best performance.
The build is minified and the filenames include the hashes.<br />
Your app is ready to be deployed!
See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information.
### `yarn eject`
**Note: this is a one-way operation. Once you `eject`, you cant go back!**
If you arent satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project.
Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point youre on your own.
You dont have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldnt feel obligated to use this feature. However we understand that this tool wouldnt be useful if you couldnt customize it when you are ready for it.
## Learn More
You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started).
To learn React, check out the [React documentation](https://reactjs.org/).
### Code Splitting
This section has moved here: https://facebook.github.io/create-react-app/docs/code-splitting
### Analyzing the Bundle Size
This section has moved here: https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size
### Making a Progressive Web App
This section has moved here: https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app
### Advanced Configuration
This section has moved here: https://facebook.github.io/create-react-app/docs/advanced-configuration
### Deployment
This section has moved here: https://facebook.github.io/create-react-app/docs/deployment
### `yarn build` fails to minify
This section has moved here: https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify

View File

@ -0,0 +1,34 @@
{
"name": "react-spa",
"version": "0.1.0",
"private": true,
"dependencies": {
"@testing-library/jest-dom": "^4.2.4",
"@testing-library/react": "^9.3.2",
"@testing-library/user-event": "^7.1.2",
"react": "^16.13.1",
"react-dom": "^16.13.1",
"react-scripts": "3.4.1"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": "react-app"
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

View File

@ -0,0 +1,43 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="Web site created using create-react-app"
/>
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<!--
manifest.json provides metadata used when your web app is installed on a
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
-->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
Only files inside the `public` folder can be referenced from the HTML.
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>React App</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
You can add webfonts, meta tags, or analytics to this file.
The build step will place the bundled scripts into the <body> tag.
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

View File

@ -0,0 +1,25 @@
{
"short_name": "React App",
"name": "Create React App Sample",
"icons": [
{
"src": "favicon.ico",
"sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon"
},
{
"src": "logo192.png",
"type": "image/png",
"sizes": "192x192"
},
{
"src": "logo512.png",
"type": "image/png",
"sizes": "512x512"
}
],
"start_url": ".",
"display": "standalone",
"theme_color": "#000000",
"background_color": "#ffffff"
}

View File

@ -0,0 +1,3 @@
# https://www.robotstxt.org/robotstxt.html
User-agent: *
Disallow:

View File

@ -0,0 +1,40 @@
.App {
text-align: center;
width: 100%;
}
.App-logo {
height: 40vmin;
pointer-events: none;
}
@media (prefers-reduced-motion: no-preference) {
.App-logo {
animation: App-logo-spin infinite 20s linear;
}
}
.App-header {
background-color: #282c34;
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-size: calc(10px + 2vmin);
color: white;
width: 100%;
}
.App-link {
color: #61dafb;
}
@keyframes App-logo-spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}

66
demo/react-spa/src/App.js vendored Normal file
View File

@ -0,0 +1,66 @@
import React, { useState } from 'react';
import './App.css';
function App() {
const [ resp, changeResponse ] = useState(null);
const [ username, changeUsername ] = useState('');
const [ password, changePassword ] = useState('');
function onSubmit(e) {
e.preventDefault();
return fetch('http://localhost:8000/dj-rest-auth/login/', {
method: 'POST',
credentials: 'omit',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
},
body: JSON.stringify({username, password})
}).then(resp => resp.json()).then(data => {
changeResponse(data)
}).catch(error => console.log('error ->', error))
}
return (
<div className="App">
<header className="App-header">
<h1>
Login
</h1>
<div className={'help-text'}>
Inspect the network requests in your browser to view headers returned by dj-rest-auth.
</div>
<div>
{resp &&
<div className={'response'}>
<code>
{JSON.stringify(resp)}
</code>
</div>
}
</div>
<div>
<form onSubmit={onSubmit}>
<div>
<input
onChange={(e) => changeUsername(e.target.value)}
value={username}
type={'input'}
name={'username'}/>
</div>
<div>
<input
onChange={(e) => changePassword(e.target.value)}
value={password}
type={'password'}
name={'password'}/>
</div>
<button type={'submit'}>Submit</button>
</form>
</div>
</header>
</div>
);
}
export default App;

View File

@ -0,0 +1,9 @@
import React from 'react';
import { render } from '@testing-library/react';
import App from './App';
test('renders learn react link', () => {
const { getByText } = render(<App />);
const linkElement = getByText(/learn react/i);
expect(linkElement).toBeInTheDocument();
});

View File

@ -0,0 +1,48 @@
body {
margin: 0;
width: 100%;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
display: flex;
flex-direction: column;
}
body div {
flex-direction: row;
text-align: center;
display: flex;
justify-content: center;
}
ul {
width: 240px;
font-size: 11px;
}
code {
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
monospace;
word-break: break-all;
height: 200px;
color: #0f0f0f;
}
.response {
margin: 20px;
background-color: #eee;
width: 80%;
height: 200px;
overflow: scroll;
}
.help-text {
font-size: 11px;
margin: 20px;
}
form > div {
margin: 20px;
}

17
demo/react-spa/src/index.js vendored Normal file
View File

@ -0,0 +1,17 @@
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);
// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://bit.ly/CRA-PWA
serviceWorker.unregister();

View File

@ -0,0 +1,7 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 841.9 595.3">
<g fill="#61DAFB">
<path d="M666.3 296.5c0-32.5-40.7-63.3-103.1-82.4 14.4-63.6 8-114.2-20.2-130.4-6.5-3.8-14.1-5.6-22.4-5.6v22.3c4.6 0 8.3.9 11.4 2.6 13.6 7.8 19.5 37.5 14.9 75.7-1.1 9.4-2.9 19.3-5.1 29.4-19.6-4.8-41-8.5-63.5-10.9-13.5-18.5-27.5-35.3-41.6-50 32.6-30.3 63.2-46.9 84-46.9V78c-27.5 0-63.5 19.6-99.9 53.6-36.4-33.8-72.4-53.2-99.9-53.2v22.3c20.7 0 51.4 16.5 84 46.6-14 14.7-28 31.4-41.3 49.9-22.6 2.4-44 6.1-63.6 11-2.3-10-4-19.7-5.2-29-4.7-38.2 1.1-67.9 14.6-75.8 3-1.8 6.9-2.6 11.5-2.6V78.5c-8.4 0-16 1.8-22.6 5.6-28.1 16.2-34.4 66.7-19.9 130.1-62.2 19.2-102.7 49.9-102.7 82.3 0 32.5 40.7 63.3 103.1 82.4-14.4 63.6-8 114.2 20.2 130.4 6.5 3.8 14.1 5.6 22.5 5.6 27.5 0 63.5-19.6 99.9-53.6 36.4 33.8 72.4 53.2 99.9 53.2 8.4 0 16-1.8 22.6-5.6 28.1-16.2 34.4-66.7 19.9-130.1 62-19.1 102.5-49.9 102.5-82.3zm-130.2-66.7c-3.7 12.9-8.3 26.2-13.5 39.5-4.1-8-8.4-16-13.1-24-4.6-8-9.5-15.8-14.4-23.4 14.2 2.1 27.9 4.7 41 7.9zm-45.8 106.5c-7.8 13.5-15.8 26.3-24.1 38.2-14.9 1.3-30 2-45.2 2-15.1 0-30.2-.7-45-1.9-8.3-11.9-16.4-24.6-24.2-38-7.6-13.1-14.5-26.4-20.8-39.8 6.2-13.4 13.2-26.8 20.7-39.9 7.8-13.5 15.8-26.3 24.1-38.2 14.9-1.3 30-2 45.2-2 15.1 0 30.2.7 45 1.9 8.3 11.9 16.4 24.6 24.2 38 7.6 13.1 14.5 26.4 20.8 39.8-6.3 13.4-13.2 26.8-20.7 39.9zm32.3-13c5.4 13.4 10 26.8 13.8 39.8-13.1 3.2-26.9 5.9-41.2 8 4.9-7.7 9.8-15.6 14.4-23.7 4.6-8 8.9-16.1 13-24.1zM421.2 430c-9.3-9.6-18.6-20.3-27.8-32 9 .4 18.2.7 27.5.7 9.4 0 18.7-.2 27.8-.7-9 11.7-18.3 22.4-27.5 32zm-74.4-58.9c-14.2-2.1-27.9-4.7-41-7.9 3.7-12.9 8.3-26.2 13.5-39.5 4.1 8 8.4 16 13.1 24 4.7 8 9.5 15.8 14.4 23.4zM420.7 163c9.3 9.6 18.6 20.3 27.8 32-9-.4-18.2-.7-27.5-.7-9.4 0-18.7.2-27.8.7 9-11.7 18.3-22.4 27.5-32zm-74 58.9c-4.9 7.7-9.8 15.6-14.4 23.7-4.6 8-8.9 16-13 24-5.4-13.4-10-26.8-13.8-39.8 13.1-3.1 26.9-5.8 41.2-7.9zm-90.5 125.2c-35.4-15.1-58.3-34.9-58.3-50.6 0-15.7 22.9-35.6 58.3-50.6 8.6-3.7 18-7 27.7-10.1 5.7 19.6 13.2 40 22.5 60.9-9.2 20.8-16.6 41.1-22.2 60.6-9.9-3.1-19.3-6.5-28-10.2zM310 490c-13.6-7.8-19.5-37.5-14.9-75.7 1.1-9.4 2.9-19.3 5.1-29.4 19.6 4.8 41 8.5 63.5 10.9 13.5 18.5 27.5 35.3 41.6 50-32.6 30.3-63.2 46.9-84 46.9-4.5-.1-8.3-1-11.3-2.7zm237.2-76.2c4.7 38.2-1.1 67.9-14.6 75.8-3 1.8-6.9 2.6-11.5 2.6-20.7 0-51.4-16.5-84-46.6 14-14.7 28-31.4 41.3-49.9 22.6-2.4 44-6.1 63.6-11 2.3 10.1 4.1 19.8 5.2 29.1zm38.5-66.7c-8.6 3.7-18 7-27.7 10.1-5.7-19.6-13.2-40-22.5-60.9 9.2-20.8 16.6-41.1 22.2-60.6 9.9 3.1 19.3 6.5 28.1 10.2 35.4 15.1 58.3 34.9 58.3 50.6-.1 15.7-23 35.6-58.4 50.6zM320.8 78.4z"/>
<circle cx="420.9" cy="296.5" r="45.7"/>
<path d="M520.5 78.1z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.6 KiB

141
demo/react-spa/src/serviceWorker.js vendored Normal file
View File

@ -0,0 +1,141 @@
// This optional code is used to register a service worker.
// register() is not called by default.
// This lets the app load faster on subsequent visits in production, and gives
// it offline capabilities. However, it also means that developers (and users)
// will only see deployed updates on subsequent visits to a page, after all the
// existing tabs open on the page have been closed, since previously cached
// resources are updated in the background.
// To learn more about the benefits of this model and instructions on how to
// opt-in, read https://bit.ly/CRA-PWA
const isLocalhost = Boolean(
window.location.hostname === 'localhost' ||
// [::1] is the IPv6 localhost address.
window.location.hostname === '[::1]' ||
// 127.0.0.0/8 are considered localhost for IPv4.
window.location.hostname.match(
/^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/
)
);
export function register(config) {
if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
// The URL constructor is available in all browsers that support SW.
const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href);
if (publicUrl.origin !== window.location.origin) {
// Our service worker won't work if PUBLIC_URL is on a different origin
// from what our page is served on. This might happen if a CDN is used to
// serve assets; see https://github.com/facebook/create-react-app/issues/2374
return;
}
window.addEventListener('load', () => {
const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;
if (isLocalhost) {
// This is running on localhost. Let's check if a service worker still exists or not.
checkValidServiceWorker(swUrl, config);
// Add some additional logging to localhost, pointing developers to the
// service worker/PWA documentation.
navigator.serviceWorker.ready.then(() => {
console.log(
'This web app is being served cache-first by a service ' +
'worker. To learn more, visit https://bit.ly/CRA-PWA'
);
});
} else {
// Is not localhost. Just register service worker
registerValidSW(swUrl, config);
}
});
}
}
function registerValidSW(swUrl, config) {
navigator.serviceWorker
.register(swUrl)
.then(registration => {
registration.onupdatefound = () => {
const installingWorker = registration.installing;
if (installingWorker == null) {
return;
}
installingWorker.onstatechange = () => {
if (installingWorker.state === 'installed') {
if (navigator.serviceWorker.controller) {
// At this point, the updated precached content has been fetched,
// but the previous service worker will still serve the older
// content until all client tabs are closed.
console.log(
'New content is available and will be used when all ' +
'tabs for this page are closed. See https://bit.ly/CRA-PWA.'
);
// Execute callback
if (config && config.onUpdate) {
config.onUpdate(registration);
}
} else {
// At this point, everything has been precached.
// It's the perfect time to display a
// "Content is cached for offline use." message.
console.log('Content is cached for offline use.');
// Execute callback
if (config && config.onSuccess) {
config.onSuccess(registration);
}
}
}
};
};
})
.catch(error => {
console.error('Error during service worker registration:', error);
});
}
function checkValidServiceWorker(swUrl, config) {
// Check if the service worker can be found. If it can't reload the page.
fetch(swUrl, {
headers: { 'Service-Worker': 'script' },
})
.then(response => {
// Ensure service worker exists, and that we really are getting a JS file.
const contentType = response.headers.get('content-type');
if (
response.status === 404 ||
(contentType != null && contentType.indexOf('javascript') === -1)
) {
// No service worker found. Probably a different app. Reload the page.
navigator.serviceWorker.ready.then(registration => {
registration.unregister().then(() => {
window.location.reload();
});
});
} else {
// Service worker found. Proceed as normal.
registerValidSW(swUrl, config);
}
})
.catch(() => {
console.log(
'No internet connection found. App is running in offline mode.'
);
});
}
export function unregister() {
if ('serviceWorker' in navigator) {
navigator.serviceWorker.ready
.then(registration => {
registration.unregister();
})
.catch(error => {
console.error(error.message);
});
}
}

5
demo/react-spa/src/setupTests.js vendored Normal file
View File

@ -0,0 +1,5 @@
// jest-dom adds custom jest matchers for asserting on DOM nodes.
// allows you to do things like:
// expect(element).toHaveTextContent(/react/i)
// learn more: https://github.com/testing-library/jest-dom
import '@testing-library/jest-dom/extend-expect';

View File

@ -1,6 +1,8 @@
django>=1.9.0
django-rest-auth==0.9.5
djangorestframework>=3.7.0
git+https://github.com/jazzband/dj-rest-auth.git@master
djangorestframework>=3.11.0
djangorestframework-simplejwt==4.4.0
django-allauth>=0.24.1
six==1.9.0
django-rest-swagger==2.0.7
django-cors-headers==3.2.1
coreapi==2.3.3

View File

@ -4,10 +4,10 @@
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="Django-rest-auth demo">
<meta name="author" content="Tivix, Inc.">
<meta name="description" content="Django-dj-rest-auth demo">
<meta name="author" content="iMerica, Inc.">
<title>django-rest-auth demo</title>
<title>dj-rest-auth demo</title>
<!-- Latest compiled and minified CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
@ -53,13 +53,13 @@
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="/">django-rest-auth demo</a>
<a class="navbar-brand" href="/">dj-rest-auth demo</a>
</div>
<div class="collapse navbar-collapse">
<ul class="nav navbar-nav">
<li class="active"><a href="/">Demo</a></li>
<li><a target="_blank" href="http://django-rest-auth.readthedocs.org/en/latest/">Documentation</a></li>
<li><a target="_blank" href="https://github.com/Tivix/django-rest-auth">Source code</a></li>
<li><a target="_blank" href="http://dj-rest-auth.readthedocs.org/en/latest/">Documentation</a></li>
<li><a target="_blank" href="https://github.com/jazzband/dj-rest-auth">Source code</a></li>
<li><a target="_blank" href="{% url 'api_docs' %}">API Docs</a></li>
</ul>
</div><!--/.nav-collapse -->

View File

@ -3,7 +3,7 @@
{% block content %}
<!-- Main jumbotron for a primary marketing message or call to action -->
<div class="jumbotron">
<h1>django-rest-auth demo</h1>
<p>Welcome in django-rest-auth demo project!</p>
<h1>dj-rest-auth demo</h1>
<p>Welcome in dj-rest-auth demo project!</p>
</div>
{% endblock %}

View File

@ -1,4 +1,5 @@
--editable .
responses>=0.5.0
djangorestframework-jwt
djangorestframework-simplejwt==4.4.0
django-allauth
coveralls>=1.11.1

View File

@ -0,0 +1,8 @@
__title__ = 'dj-rest-auth'
__description__ = 'Authentication and Registration in Django Rest Framework.'
__url__ = 'http://github.com/jazzband/dj-rest-auth'
__version__ = '1.0.6'
__author__ = '@iMerica https://github.com/iMerica'
__author_email__ = 'imichael@pm.me'
__license__ = 'MIT'
__copyright__ = 'Copyright 2020 @iMerica https://github.com/iMerica'

View File

@ -0,0 +1,40 @@
from dj_rest_auth.serializers import JWTSerializer as DefaultJWTSerializer
from dj_rest_auth.serializers import LoginSerializer as DefaultLoginSerializer
from dj_rest_auth.serializers import \
PasswordChangeSerializer as DefaultPasswordChangeSerializer
from dj_rest_auth.serializers import \
PasswordResetConfirmSerializer as DefaultPasswordResetConfirmSerializer
from dj_rest_auth.serializers import \
PasswordResetSerializer as DefaultPasswordResetSerializer
from dj_rest_auth.serializers import TokenSerializer as DefaultTokenSerializer
from dj_rest_auth.serializers import \
UserDetailsSerializer as DefaultUserDetailsSerializer
from django.conf import settings
from .utils import default_create_token, import_callable
create_token = import_callable(getattr(settings, 'REST_AUTH_TOKEN_CREATOR', default_create_token))
serializers = getattr(settings, 'REST_AUTH_SERIALIZERS', {})
TokenSerializer = import_callable(serializers.get('TOKEN_SERIALIZER', DefaultTokenSerializer))
JWTSerializer = import_callable(serializers.get('JWT_SERIALIZER', DefaultJWTSerializer))
UserDetailsSerializer = import_callable(serializers.get('USER_DETAILS_SERIALIZER', DefaultUserDetailsSerializer))
LoginSerializer = import_callable(serializers.get('LOGIN_SERIALIZER', DefaultLoginSerializer))
PasswordResetSerializer = import_callable(serializers.get(
'PASSWORD_RESET_SERIALIZER', DefaultPasswordResetSerializer
))
PasswordResetConfirmSerializer = import_callable(serializers.get(
'PASSWORD_RESET_CONFIRM_SERIALIZER', DefaultPasswordResetConfirmSerializer
))
PasswordChangeSerializer = import_callable(
serializers.get('PASSWORD_CHANGE_SERIALIZER', DefaultPasswordChangeSerializer)
)
JWT_AUTH_COOKIE = getattr(settings, 'JWT_AUTH_COOKIE', None)

View File

@ -1,11 +1,11 @@
# Czech translations of Tivix/django-rest-auth
# Czech translations of jazzband/dj-rest-auth
#
# This file is distributed under the same license as the Tivix/django-rest-auth package.
# This file is distributed under the same license as the jazzband/dj-rest-auth package.
#
msgid ""
msgstr ""
"Project-Id-Version: Tivix/django-rest-auth\n"
"Report-Msgid-Bugs-To: https://github.com/Tivix/django-rest-auth/issues\n"
"Project-Id-Version: jazzband/dj-rest-auth\n"
"Report-Msgid-Bugs-To: https://github.com/jazzband/dj-rest-auth/issues\n"
"POT-Creation-Date: 2018-06-27 23:05+0200\n"
"PO-Revision-Date: 2018-06-27 23:22+0200\n"
"Language: cs\n"

Binary file not shown.

View File

@ -0,0 +1,123 @@
# Italian language.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-05-07 09:46+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: Francesco Pinzauti <info@pinzauti.tech>\n"
"Language-Team: \n"
"Language: it\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: .\registration\serializers.py:67
msgid "View is not defined, pass it as a context variable"
msgstr "\"view\" non è definito, passalo come variabile di contesto"
#: .\registration\serializers.py:72
msgid "Define adapter_class in view"
msgstr "Definisci \"adapter_class\" in view"
#: .\registration\serializers.py:91
msgid "Define callback_url in view"
msgstr "Definisci \"callback_url\" in view"
#: .\registration\serializers.py:95
msgid "Define client_class in view"
msgstr "Definisci \"client_class\" in view"
#: .\registration\serializers.py:116
msgid "Incorrect input. access_token or code is required."
msgstr "Input errato. È richiesto \"access_token\" o \"code\"."
#: .\registration\serializers.py:125
msgid "Incorrect value"
msgstr "Valore errato"
#: .\registration\serializers.py:139
msgid "User is already registered with this e-mail address."
msgstr "Un altro utente è già registrato con questo indirizzo e-mail."
#: .\registration\serializers.py:185
msgid "A user is already registered with this e-mail address."
msgstr "Un altro utente è già registrato con questo indirizzo e-mail."
#: .\registration\serializers.py:193
msgid "The two password fields didn't match."
msgstr "Le password non corrispondono."
#: .\registration\views.py:47
msgid "Verification e-mail sent."
msgstr "E-mail di verifica inviata."
#: .\registration\views.py:95
msgid "ok"
msgstr "ok"
#: .\serializers.py:32
msgid "Must include \"email\" and \"password\"."
msgstr "Deve includere \"email\" e \"password\"."
#: .\serializers.py:43
msgid "Must include \"username\" and \"password\"."
msgstr "Deve includere \"email\" e \"password\"."
#: .\serializers.py:56
msgid "Must include either \"username\" or \"email\" and \"password\"."
msgstr "Deve includere o \"username\" o \"email\" e \"password\"."
#: .\serializers.py:97
msgid "User account is disabled."
msgstr "L'account è disabilitato."
#: .\serializers.py:100
msgid "Unable to log in with provided credentials."
msgstr "Impossibile accedere con le credenziali fornite."
#: .\serializers.py:109
msgid "E-mail is not verified."
msgstr "L'e-mail non è verificata."
#: .\serializers.py:264
msgid "Your old password was entered incorrectly. Please enter it again."
msgstr "La tua password precedente non è corretta. Inseriscila nuovamente."
#: .\views.py:139
msgid "Successfully logged out."
msgstr "Disconnesso con successo."
#: .\views.py:161
msgid "Refresh token was not included in request data."
msgstr "Il \"Refresh token\" non è presente nei dati della richiesta."
#: .\views.py:171 .\views.py:175
msgid "An error has occurred."
msgstr "Si è verificato un errore."
#: .\views.py:180
msgid ""
"Neither cookies or blacklist are enabled, so the token has not been deleted "
"server side. Please make sure the token is deleted client side."
msgstr ""
"Né i cookies né la blacklist sono abilitati, quindi il token non è stato eliminato "
"lato server. Assicurarsi che il token sia eliminato lato client."
#: .\views.py:230
msgid "Password reset e-mail has been sent."
msgstr "L'e-mail per il recupero della password è stata inviata."
#: .\views.py:256
msgid "Password has been reset with the new password."
msgstr "Password aggiornata."
#: .\views.py:278
msgid "New password has been saved."
msgstr "Nuova password salvata."

Binary file not shown.

View File

@ -0,0 +1,101 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-05-23 21:56-0800\n"
"PO-Revision-Date: 2020-05-23 00:56+0300\n"
"Last-Translator: \n"
"Language-Team: \n"
"Language: ru\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
"%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n"
"%100>=11 && n%100<=14)? 2 : 3);\n"
"X-Generator: Poedit 2.3.1\n"
#: registration/serializers.py:53
msgid "View is not defined, pass it as a context variable"
msgstr "View невідомий, передайте його як змінну контексту"
#: registration/serializers.py:58
msgid "Define adapter_class in view"
msgstr "Встановіть adapter_class у view"
#: registration/serializers.py:77
msgid "Define callback_url in view"
msgstr "Встановіть callback_url у view"
#: registration/serializers.py:81
msgid "Define client_class in view"
msgstr "Встановіть client_class у view"
#: registration/serializers.py:102
msgid "Incorrect input. access_token or code is required."
msgstr "Некоректне введення. Необхідний access_token або code."
#: registration/serializers.py:111
msgid "Incorrect value"
msgstr "Некоректне значення"
#: registration/serializers.py:140
msgid "A user is already registered with this e-mail address."
msgstr "Користувач з таким e-mail адресою вже зареєстрований."
#: registration/serializers.py:148
msgid "The two password fields didn't match."
msgstr "Паролі не збігаються."
#: registration/views.py:44
msgid "Verification e-mail sent."
msgstr "Лист з підтвердженням вислано на email."
#: registration/views.py:91
msgid "ok"
msgstr "добре"
#: serializers.py:30
msgid "Must include \"email\" and \"password\"."
msgstr "Має включати \"email\" и \"пароль\"."
#: serializers.py:41
msgid "Must include \"username\" and \"password\"."
msgstr "Має включати \"юзернейм\" и \"пароль\"."
#: serializers.py:54
msgid "Must include either \"username\" or \"email\" and \"password\"."
msgstr "Повинно включати або \"юзернейм\" либо \"email\" и \"пароль\"."
#: serializers.py:95
msgid "User account is disabled."
msgstr "Користувач вимкнений."
#: serializers.py:98
msgid "Unable to log in with provided credentials."
msgstr "Неможливо увійти в систему з зазначеними обліковими даними."
#: serializers.py:107
msgid "E-mail is not verified."
msgstr "E-mail не підтверджено."
#: views.py:126
msgid "Successfully logged out."
msgstr "Успішно вийшли."
#: views.py:174
msgid "Password reset e-mail has been sent."
msgstr "Лист з інструкціями по відновленню пароля вислано."
#: views.py:200
msgid "Password has been reset with the new password."
msgstr "Пароль змінено на новий."
#: views.py:222
msgid "New password has been saved."
msgstr "Новий пароль збережений."

4
dj_rest_auth/models.py Normal file
View File

@ -0,0 +1,4 @@
from django.conf import settings
from django.utils.module_loading import import_string
TokenModel = import_string(getattr(settings, 'REST_AUTH_TOKEN_MODEL', 'rest_framework.authtoken.models.Token'))

View File

@ -1,19 +1,17 @@
from dj_rest_auth.registration.serializers import \
RegisterSerializer as DefaultRegisterSerializer
from django.conf import settings
from rest_framework.permissions import AllowAny
from rest_auth.registration.serializers import (
RegisterSerializer as DefaultRegisterSerializer)
from ..utils import import_callable
from ..utils import import_callable
serializers = getattr(settings, 'REST_AUTH_REGISTER_SERIALIZERS', {})
RegisterSerializer = import_callable(
serializers.get('REGISTER_SERIALIZER', DefaultRegisterSerializer))
RegisterSerializer = import_callable(serializers.get('REGISTER_SERIALIZER', DefaultRegisterSerializer))
def register_permission_classes():
permission_classes = [AllowAny, ]
for klass in getattr(settings, 'REST_AUTH_REGISTER_PERMISSION_CLASSES', tuple()):
permission_classes.append(import_callable(klass))
permission_classes.append(klass)
return tuple(permission_classes)

View File

@ -1,6 +1,8 @@
from django.contrib.auth import get_user_model
from django.http import HttpRequest
from django.utils.translation import ugettext_lazy as _
from django.contrib.auth import get_user_model
from requests.exceptions import HTTPError
from rest_framework import serializers
try:
from allauth.account import app_settings as allauth_settings
@ -14,9 +16,6 @@ try:
except ImportError:
raise ImportError("allauth needs to be added to INSTALLED_APPS.")
from rest_framework import serializers
from requests.exceptions import HTTPError
class SocialAccountSerializer(serializers.ModelSerializer):
"""

View File

@ -1,5 +1,5 @@
from django.views.generic import TemplateView
from django.conf.urls import url
from django.views.generic import TemplateView
from .views import RegisterView, VerifyEmailView

View File

@ -1,34 +1,30 @@
from allauth.account import app_settings as allauth_settings
from allauth.account.adapter import get_adapter
from allauth.account.utils import complete_signup
from allauth.account.views import ConfirmEmailView
from allauth.socialaccount import signals
from allauth.socialaccount.adapter import get_adapter as get_social_adapter
from allauth.socialaccount.models import SocialAccount
from dj_rest_auth.app_settings import (JWTSerializer, TokenSerializer,
create_token)
from dj_rest_auth.models import TokenModel
from dj_rest_auth.registration.serializers import (SocialAccountSerializer,
SocialConnectSerializer,
SocialLoginSerializer,
VerifyEmailSerializer)
from dj_rest_auth.utils import jwt_encode
from dj_rest_auth.views import LoginView
from django.conf import settings
from django.utils.decorators import method_decorator
from django.utils.translation import ugettext_lazy as _
from django.views.decorators.debug import sensitive_post_parameters
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.permissions import (AllowAny,
IsAuthenticated)
from rest_framework.generics import CreateAPIView, ListAPIView, GenericAPIView
from rest_framework.exceptions import NotFound
from rest_framework import status
from rest_framework.exceptions import NotFound
from rest_framework.generics import CreateAPIView, GenericAPIView, ListAPIView
from rest_framework.permissions import AllowAny, IsAuthenticated
from rest_framework.response import Response
from rest_framework.views import APIView
from allauth.account.adapter import get_adapter
from allauth.account.views import ConfirmEmailView
from allauth.account.utils import complete_signup
from allauth.account import app_settings as allauth_settings
from allauth.socialaccount import signals
from allauth.socialaccount.adapter import get_adapter as get_social_adapter
from allauth.socialaccount.models import SocialAccount
from rest_auth.app_settings import (TokenSerializer,
JWTSerializer,
create_token)
from rest_auth.models import TokenModel
from rest_auth.registration.serializers import (VerifyEmailSerializer,
SocialLoginSerializer,
SocialAccountSerializer,
SocialConnectSerializer)
from rest_auth.utils import jwt_encode
from rest_auth.views import LoginView
from .app_settings import RegisterSerializer, register_permission_classes
sensitive_post_parameters_m = method_decorator(
@ -54,11 +50,12 @@ class RegisterView(CreateAPIView):
if getattr(settings, 'REST_USE_JWT', False):
data = {
'user': user,
'token': self.token
'access_token': self.access_token,
'refresh_token': self.refresh_token
}
return JWTSerializer(data).data
return JWTSerializer(data, context=self.get_serializer_context()).data
else:
return TokenSerializer(user.auth_token).data
return TokenSerializer(user.auth_token, context=self.get_serializer_context()).data
def create(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
@ -73,7 +70,7 @@ class RegisterView(CreateAPIView):
def perform_create(self, serializer):
user = serializer.save(self.request)
if getattr(settings, 'REST_USE_JWT', False):
self.token = jwt_encode(user)
self.access_token, self.refresh_token = jwt_encode(user)
else:
create_token(self.token_model, user, serializer)

View File

@ -1,16 +1,18 @@
from django.contrib.auth import get_user_model, authenticate
from django.conf import settings
from django.contrib.auth import authenticate, get_user_model
from django.contrib.auth.forms import PasswordResetForm, SetPasswordForm
from django.contrib.auth.tokens import default_token_generator
from django.utils.http import urlsafe_base64_decode as uid_decoder
from django.utils.translation import ugettext_lazy as _
from django.utils.encoding import force_text
from rest_framework import serializers, exceptions
from django.utils.http import urlsafe_base64_decode as uid_decoder
from django.utils.module_loading import import_string
try:
from django.utils.translation import gettext_lazy as _
except ImportError:
from django.utils.translation import ugettext_lazy as _
from rest_framework import exceptions, serializers
from rest_framework.exceptions import ValidationError
from .models import TokenModel
from .utils import import_callable
# Get the UserModel
UserModel = get_user_model()
@ -102,7 +104,7 @@ class LoginSerializer(serializers.Serializer):
raise exceptions.ValidationError(msg)
# If required, is the email verified?
if 'rest_auth.registration' in settings.INSTALLED_APPS:
if 'dj_rest_auth.registration' in settings.INSTALLED_APPS:
from allauth.account import app_settings
if app_settings.EMAIL_VERIFICATION == app_settings.EmailVerificationMethod.MANDATORY:
email_address = user.emailaddress_set.get(email=user.email)
@ -137,7 +139,8 @@ class JWTSerializer(serializers.Serializer):
"""
Serializer for JWT authentication.
"""
token = serializers.CharField()
access_token = serializers.CharField()
refresh_token = serializers.CharField()
user = serializers.SerializerMethodField()
def get_user(self, obj):
@ -146,9 +149,14 @@ class JWTSerializer(serializers.Serializer):
JWTSerializer. Defining it here to avoid circular imports
"""
rest_auth_serializers = getattr(settings, 'REST_AUTH_SERIALIZERS', {})
JWTUserDetailsSerializer = import_callable(
rest_auth_serializers.get('USER_DETAILS_SERIALIZER', UserDetailsSerializer)
JWTUserDetailsSerializer = import_string(
rest_auth_serializers.get(
'USER_DETAILS_SERIALIZER',
'dj_rest_auth.serializers.UserDetailsSerializer'
)
)
user_data = JWTUserDetailsSerializer(obj['user'], context=self.context).data
return user_data
@ -188,7 +196,7 @@ class PasswordResetSerializer(serializers.Serializer):
class PasswordResetConfirmSerializer(serializers.Serializer):
"""
Serializer for requesting a password reset e-mail.
Serializer for confirming a password reset attempt.
"""
new_password1 = serializers.CharField(max_length=128)
new_password2 = serializers.CharField(max_length=128)
@ -210,6 +218,9 @@ class PasswordResetConfirmSerializer(serializers.Serializer):
except (TypeError, ValueError, OverflowError, UserModel.DoesNotExist):
raise ValidationError({'uid': ['Invalid value']})
if not default_token_generator.check_token(self.user, attrs['token']):
raise ValidationError({'token': ['Invalid value']})
self.custom_validation(attrs)
# Construct SetPasswordForm instance
self.set_password_form = self.set_password_form_class(
@ -217,8 +228,6 @@ class PasswordResetConfirmSerializer(serializers.Serializer):
)
if not self.set_password_form.is_valid():
raise serializers.ValidationError(self.set_password_form.errors)
if not default_token_generator.check_token(self.user, attrs['token']):
raise ValidationError({'token': ['Invalid value']})
return attrs

View File

@ -1,6 +1,7 @@
from django.conf import settings
from django.http import HttpRequest
from rest_framework import serializers
# Import is needed only if we are using social login, in which
# case the allauth.socialaccount will be declared
if 'allauth.socialaccount' in settings.INSTALLED_APPS:
@ -8,7 +9,7 @@ if 'allauth.socialaccount' in settings.INSTALLED_APPS:
from allauth.socialaccount.models import SocialToken
from allauth.socialaccount.providers.oauth.client import OAuthError
from rest_auth.registration.serializers import SocialConnectMixin
from dj_rest_auth.registration.serializers import SocialConnectMixin
class TwitterLoginSerializer(serializers.Serializer):

View File

@ -0,0 +1,45 @@
# Moved in Django 1.8 from django to tests/auth_tests/urls.py
from django.conf.urls import url
from django.contrib.auth.decorators import login_required
from django.contrib.auth.urls import urlpatterns
try:
from django.contrib.auth.views import (
logout, login, password_reset,
password_change, password_reset_confirm
)
except ImportError:
from django.contrib.auth.views import (
LoginView, LogoutView, PasswordResetView,
PasswordChangeView, PasswordResetConfirmView
)
logout = LogoutView.as_view()
login = LoginView.as_view()
password_reset = PasswordResetView.as_view()
password_change = PasswordChangeView.as_view()
password_reset_confirm = PasswordResetConfirmView.as_view()
# special urls for auth test cases
urlpatterns += [
url(r'^logout/custom_query/$', logout, dict(redirect_field_name='follow')),
url(r'^logout/next_page/$', logout, dict(next_page='/somewhere/')),
url(r'^logout/next_page/named/$', logout, dict(next_page='password_reset')),
url(r'^password_reset_from_email/$', password_reset, dict(from_email='staffmember@example.com')),
url(r'^password_reset/custom_redirect/$', password_reset, dict(post_reset_redirect='/custom/')),
url(r'^password_reset/custom_redirect/named/$', password_reset, dict(post_reset_redirect='password_reset')),
url(r'^password_reset/html_email_template/$', password_reset,
dict(html_email_template_name='registration/html_password_reset_email.html')),
url(r'^reset/custom/(?P<uidb64>[0-9A-Za-z_\-]+)/(?P<token>[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})/$',
password_reset_confirm,
dict(post_reset_redirect='/custom/')),
url(r'^reset/custom/named/(?P<uidb64>[0-9A-Za-z_\-]+)/(?P<token>[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})/$',
password_reset_confirm,
dict(post_reset_redirect='password_reset')),
url(r'^password_change/custom/$', password_change, dict(post_change_redirect='/custom/')),
url(r'^password_change/custom/named/$', password_change, dict(post_change_redirect='password_reset')),
url(r'^admin_password_reset/$', password_reset, dict(is_admin_site=True)),
url(r'^login_required/$', login_required(password_reset)),
url(r'^login_required_login_url/$', login_required(password_reset, login_url='/somewhere/')),
]

View File

@ -1,11 +1,9 @@
import json
from django.conf import settings
from django.test.client import Client, MULTIPART_CONTENT
from django.test.client import MULTIPART_CONTENT, Client
from django.utils.encoding import force_text
from rest_framework import status
from rest_framework import permissions
from rest_framework import permissions, status
try:
from django.urls import reverse

View File

@ -0,0 +1,4 @@
django-allauth>=0.25.0
responses>=0.3.0
flake8==2.4.0
djangorestframework-simplejwt==4.4.0

View File

@ -1,8 +1,11 @@
import logging
import os
import sys
PROJECT_ROOT = os.path.abspath(os.path.split(os.path.split(__file__)[0])[0])
logging.disable(logging.CRITICAL)
ROOT_URLCONF = 'urls'
STATIC_URL = '/static/'
STATIC_ROOT = '%s/staticserve' % PROJECT_ROOT
@ -65,11 +68,12 @@ TEMPLATES = [
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.SessionAuthentication',
'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
'dj_rest_auth.utils.JWTCookieAuthentication',
)
}
INSTALLED_APPS = [
'django.contrib.messages',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.humanize',
@ -88,10 +92,10 @@ INSTALLED_APPS = [
'rest_framework',
'rest_framework.authtoken',
'rest_auth',
'rest_auth.registration',
'dj_rest_auth',
'dj_rest_auth.registration',
'rest_framework_jwt'
'rest_framework_simplejwt.token_blacklist'
]
SECRET_KEY = "38dh*skf8sjfhs287dh&^hd8&3hdg*j2&sd"

View File

@ -1,17 +1,17 @@
from django.test import TestCase, override_settings
from django.contrib.auth import get_user_model
from django.core import mail
from django.conf import settings
from django.utils.encoding import force_text
import json
from allauth.account import app_settings as account_app_settings
from django.conf import settings
from django.contrib.auth import get_user_model
from django.core import mail
from django.test import TestCase, override_settings
from django.utils.encoding import force_text
from rest_framework import status
from rest_framework.test import APIRequestFactory
from rest_auth.registration.views import RegisterView
from rest_auth.registration.app_settings import register_permission_classes
from .mixins import TestsMixin, CustomPermissionClass
from dj_rest_auth.registration.app_settings import register_permission_classes
from dj_rest_auth.registration.views import RegisterView
from .mixins import CustomPermissionClass, TestsMixin
try:
from django.urls import reverse
@ -154,8 +154,8 @@ class APIBasicTests(TestsMixin, TestCase):
get_user_model().objects.create_user(self.USERNAME, '', self.PASS)
self.post(self.login_url, data=payload, status_code=200)
self.assertEqual('token' in self.response.json.keys(), True)
self.token = self.response.json['token']
self.assertEqual('access_token' in self.response.json.keys(), True)
self.token = self.response.json['access_token']
def test_login_by_email(self):
# starting test without allauth app
@ -384,7 +384,7 @@ class APIBasicTests(TestsMixin, TestCase):
"password": self.PASS
}
self.post(self.login_url, data=payload, status_code=200)
self.token = self.response.json['token']
self.token = self.response.json['access_token']
self.get(self.user_url, status_code=200)
self.patch(self.user_url, data=self.BASIC_USER_DATA, status_code=200)
@ -409,7 +409,6 @@ class APIBasicTests(TestsMixin, TestCase):
@override_settings(REST_AUTH_REGISTER_PERMISSION_CLASSES=(CustomPermissionClass,))
def test_registration_with_custom_permission_class(self):
class CustomRegisterView(RegisterView):
permission_classes = register_permission_classes()
authentication_classes = ()
@ -428,7 +427,7 @@ class APIBasicTests(TestsMixin, TestCase):
self.post(self.register_url, data={}, status_code=400)
result = self.post(self.register_url, data=self.REGISTRATION_DATA, status_code=201)
self.assertIn('token', result.data)
self.assertIn('access_token', result.data)
self.assertEqual(get_user_model().objects.all().count(), user_count + 1)
self._login()
@ -479,7 +478,7 @@ class APIBasicTests(TestsMixin, TestCase):
)
# verify email
email_confirmation = new_user.emailaddress_set.get(email=self.EMAIL)\
email_confirmation = new_user.emailaddress_set.get(email=self.EMAIL) \
.emailconfirmation_set.order_by('-created')[0]
self.post(
self.verify_email_url,
@ -516,3 +515,86 @@ class APIBasicTests(TestsMixin, TestCase):
self.post(self.login_url, data=payload, status_code=status.HTTP_200_OK)
self.get(self.logout_url, status_code=status.HTTP_405_METHOD_NOT_ALLOWED)
@override_settings(REST_USE_JWT=True)
@override_settings(JWT_AUTH_COOKIE='jwt-auth')
def test_login_jwt_sets_cookie(self):
payload = {
"username": self.USERNAME,
"password": self.PASS
}
get_user_model().objects.create_user(self.USERNAME, '', self.PASS)
resp = self.post(self.login_url, data=payload, status_code=200)
self.assertTrue('jwt-auth' in resp.cookies.keys())
@override_settings(REST_USE_JWT=True)
@override_settings(JWT_AUTH_COOKIE='jwt-auth')
def test_logout_jwt_deletes_cookie(self):
payload = {
"username": self.USERNAME,
"password": self.PASS
}
get_user_model().objects.create_user(self.USERNAME, '', self.PASS)
self.post(self.login_url, data=payload, status_code=200)
resp = self.post(self.logout_url, status=200)
self.assertEqual('', resp.cookies.get('jwt-auth').value)
@override_settings(REST_USE_JWT=True)
@override_settings(JWT_AUTH_COOKIE='jwt-auth')
@override_settings(REST_FRAMEWORK=dict(
DEFAULT_AUTHENTICATION_CLASSES=[
'dj_rest_auth.utils.JWTCookieAuthentication'
]
))
@override_settings(REST_SESSION_LOGIN=False)
def test_cookie_authentication(self):
payload = {
"username": self.USERNAME,
"password": self.PASS
}
get_user_model().objects.create_user(self.USERNAME, '', self.PASS)
resp = self.post(self.login_url, data=payload, status_code=200)
self.assertEqual(['jwt-auth'], list(resp.cookies.keys()))
resp = self.get('/protected-view/')
self.assertEquals(resp.status_code, 200)
@override_settings(REST_USE_JWT=True)
def test_blacklisting_not_installed(self):
settings.INSTALLED_APPS.remove('rest_framework_simplejwt.token_blacklist')
payload = {
"username": self.USERNAME,
"password": self.PASS
}
get_user_model().objects.create_user(self.USERNAME, '', self.PASS)
resp = self.post(self.login_url, data=payload, status_code=200)
token = resp.data['refresh_token']
resp = self.post(self.logout_url, status=200, data={'refresh': token})
self.assertEqual(resp.status_code, 200)
self.assertEqual(resp.data["detail"],
"Neither cookies or blacklist are enabled, so the token has not been deleted server side. "
"Please make sure the token is deleted client side.")
@override_settings(REST_USE_JWT=True)
def test_blacklisting(self):
payload = {
"username": self.USERNAME,
"password": self.PASS
}
get_user_model().objects.create_user(self.USERNAME, '', self.PASS)
resp = self.post(self.login_url, data=payload, status_code=200)
token = resp.data['refresh_token']
# test refresh token not included in request data
resp = self.post(self.logout_url, status=200)
self.assertEqual(resp.status_code, 401)
# test token is invalid or expired
resp = self.post(self.logout_url, status=200, data={'refresh': '1'})
self.assertEqual(resp.status_code, 401)
# test successful logout
resp = self.post(self.logout_url, status=200, data={'refresh': token})
self.assertEqual(resp.status_code, 200)
# test token is blacklisted
resp = self.post(self.logout_url, status=200, data={'refresh': token})
self.assertEqual(resp.status_code, 401)
# test other TokenError, AttributeError, TypeError (invalid format)
resp = self.post(self.logout_url, status=200, data=json.dumps({'refresh': token}))
self.assertEqual(resp.status_code, 500)

View File

@ -1,23 +1,21 @@
import json
from django.test import TestCase
import responses
from allauth.socialaccount.models import SocialApp
from allauth.socialaccount.providers.facebook.provider import GRAPH_API_URL
from django.contrib.auth import get_user_model
from django.test.utils import override_settings
from django.contrib.sites.models import Site
from django.test import TestCase
from django.test.utils import override_settings
from rest_framework import status
from .mixins import TestsMixin
try:
from django.urls import reverse
except ImportError:
from django.core.urlresolvers import reverse
from allauth.socialaccount.models import SocialApp
from allauth.socialaccount.providers.facebook.provider import GRAPH_API_URL
import responses
from rest_framework import status
from .mixins import TestsMixin
@override_settings(ROOT_URLCONF="tests.urls")
class TestSocialAuth(TestsMixin, TestCase):
@ -304,7 +302,7 @@ class TestSocialAuth(TestsMixin, TestCase):
}
self.post(self.fb_login_url, data=payload, status_code=200)
self.assertIn('token', self.response.json.keys())
self.assertIn('access_token', self.response.json.keys())
self.assertIn('user', self.response.json.keys())
self.assertEqual(get_user_model().objects.all().count(), users_count + 1)

View File

@ -1,20 +1,28 @@
from django.conf.urls import url, include
from allauth.socialaccount.providers.facebook.views import \
FacebookOAuth2Adapter
from allauth.socialaccount.providers.twitter.views import TwitterOAuthAdapter
from dj_rest_auth.registration.views import (SocialAccountDisconnectView,
SocialAccountListView,
SocialConnectView,
SocialLoginView)
from dj_rest_auth.social_serializers import (TwitterConnectSerializer,
TwitterLoginSerializer)
from dj_rest_auth.urls import urlpatterns
from django.conf.urls import include, url
from django.views.generic import TemplateView
from rest_framework import permissions
from rest_framework.decorators import api_view
from rest_framework.response import Response
from rest_framework.views import APIView
from . import django_urls
from allauth.socialaccount.providers.facebook.views import FacebookOAuth2Adapter
from allauth.socialaccount.providers.twitter.views import TwitterOAuthAdapter
from rest_framework.decorators import api_view
class ExampleProtectedView(APIView):
permission_classes = [permissions.IsAuthenticated]
from rest_auth.urls import urlpatterns
from rest_auth.registration.views import (
SocialLoginView, SocialConnectView, SocialAccountListView,
SocialAccountDisconnectView
)
from rest_auth.social_serializers import (
TwitterLoginSerializer, TwitterConnectSerializer
)
def get(self, *args, **kwargs):
return Response(dict(success=True))
class FacebookLogin(SocialLoginView):
@ -53,7 +61,7 @@ class TwitterLoginNoAdapter(SocialLoginView):
urlpatterns += [
url(r'^rest-registration/', include('rest_auth.registration.urls')),
url(r'^rest-registration/', include('dj_rest_auth.registration.urls')),
url(r'^test-admin/', include(django_urls)),
url(r'^account-email-verification-sent/$', TemplateView.as_view(),
name='account_email_verification_sent'),
@ -66,6 +74,7 @@ urlpatterns += [
url(r'^social-login/facebook/connect/$', FacebookConnect.as_view(), name='fb_connect'),
url(r'^social-login/twitter/connect/$', TwitterConnect.as_view(), name='tw_connect'),
url(r'^socialaccounts/$', SocialAccountListView.as_view(), name='social_account_list'),
url(r'^protected-view/$', ExampleProtectedView.as_view()),
url(r'^socialaccounts/(?P<pk>\d+)/disconnect/$', SocialAccountDisconnectView.as_view(),
name='social_account_disconnect'),
url(r'^accounts/', include('allauth.socialaccount.urls'))

View File

@ -1,9 +1,8 @@
from dj_rest_auth.views import (LoginView, LogoutView, PasswordChangeView,
PasswordResetConfirmView, PasswordResetView,
UserDetailsView)
from django.conf.urls import url
from rest_auth.views import (
LoginView, LogoutView, UserDetailsView, PasswordChangeView,
PasswordResetView, PasswordResetConfirmView
)
from django.conf import settings
urlpatterns = [
# URLs that do not require a session or valid token
@ -18,3 +17,13 @@ urlpatterns = [
url(r'^password/change/$', PasswordChangeView.as_view(),
name='rest_password_change'),
]
if getattr(settings, 'REST_USE_JWT', False):
from rest_framework_simplejwt.views import (
TokenRefreshView, TokenVerifyView,
)
urlpatterns += [
url(r'^token/verify/$', TokenVerifyView.as_view(), name='token_verify'),
url(r'^token/refresh/$', TokenRefreshView.as_view(), name='token_refresh'),
]

56
dj_rest_auth/utils.py Normal file
View File

@ -0,0 +1,56 @@
from importlib import import_module
def import_callable(path_or_callable):
if hasattr(path_or_callable, '__call__'):
return path_or_callable
else:
assert isinstance(path_or_callable, str)
package, attr = path_or_callable.rsplit('.', 1)
return getattr(import_module(package), attr)
def default_create_token(token_model, user, serializer):
token, _ = token_model.objects.get_or_create(user=user)
return token
def jwt_encode(user):
try:
from rest_framework_simplejwt.serializers import TokenObtainPairSerializer
except ImportError:
raise ImportError("rest-framework-simplejwt needs to be installed")
refresh = TokenObtainPairSerializer.get_token(user)
return refresh.access_token, refresh
try:
from rest_framework_simplejwt.authentication import JWTAuthentication
class JWTCookieAuthentication(JWTAuthentication):
"""
An authentication plugin that hopefully authenticates requests through a JSON web
token provided in a request cookie (and through the header as normal, with a
preference to the header).
"""
def authenticate(self, request):
from django.conf import settings
cookie_name = getattr(settings, 'JWT_AUTH_COOKIE', None)
header = self.get_header(request)
if header is None:
if cookie_name:
raw_token = request.COOKIES.get(cookie_name)
else:
return None
else:
raw_token = self.get_raw_token(header)
if raw_token is None:
return None
validated_token = self.get_validated_token(raw_token)
return self.get_user(validated_token), validated_token
except ImportError:
pass

View File

@ -1,25 +1,22 @@
from django.contrib.auth import (
login as django_login,
logout as django_logout
)
from django.conf import settings
from django.contrib.auth import get_user_model
from django.contrib.auth import login as django_login
from django.contrib.auth import logout as django_logout
from django.core.exceptions import ObjectDoesNotExist
from django.utils.decorators import method_decorator
from django.utils.translation import ugettext_lazy as _
from django.views.decorators.debug import sensitive_post_parameters
from rest_framework import status
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.generics import GenericAPIView, RetrieveUpdateAPIView
from rest_framework.permissions import IsAuthenticated, AllowAny
from rest_framework.permissions import AllowAny, IsAuthenticated
from rest_framework.response import Response
from rest_framework.views import APIView
from .app_settings import (
TokenSerializer, UserDetailsSerializer, LoginSerializer,
PasswordResetSerializer, PasswordResetConfirmSerializer,
PasswordChangeSerializer, JWTSerializer, create_token
)
from .app_settings import (JWTSerializer, LoginSerializer,
PasswordChangeSerializer,
PasswordResetConfirmSerializer,
PasswordResetSerializer, TokenSerializer,
UserDetailsSerializer, create_token)
from .models import TokenModel
from .utils import jwt_encode
@ -63,7 +60,7 @@ class LoginView(GenericAPIView):
self.user = self.serializer.validated_data['user']
if getattr(settings, 'REST_USE_JWT', False):
self.token = jwt_encode(self.user)
self.access_token, self.refresh_token = jwt_encode(self.user)
else:
self.token = create_token(self.token_model, self.user,
self.serializer)
@ -77,7 +74,8 @@ class LoginView(GenericAPIView):
if getattr(settings, 'REST_USE_JWT', False):
data = {
'user': self.user,
'token': self.token
'access_token': self.access_token,
'refresh_token': self.refresh_token
}
serializer = serializer_class(instance=data,
context={'request': self.request})
@ -87,14 +85,17 @@ class LoginView(GenericAPIView):
response = Response(serializer.data, status=status.HTTP_200_OK)
if getattr(settings, 'REST_USE_JWT', False):
from rest_framework_jwt.settings import api_settings as jwt_settings
if jwt_settings.JWT_AUTH_COOKIE:
cookie_name = getattr(settings, 'JWT_AUTH_COOKIE', None)
from rest_framework_simplejwt.settings import api_settings as jwt_settings
if cookie_name:
from datetime import datetime
expiration = (datetime.utcnow() + jwt_settings.JWT_EXPIRATION_DELTA)
response.set_cookie(jwt_settings.JWT_AUTH_COOKIE,
self.token,
expires=expiration,
httponly=True)
expiration = (datetime.utcnow() + jwt_settings.ACCESS_TOKEN_LIFETIME)
response.set_cookie(
cookie_name,
self.access_token,
expires=expiration,
httponly=True
)
return response
def post(self, request, *args, **kwargs):
@ -129,15 +130,58 @@ class LogoutView(APIView):
return self.logout(request)
def logout(self, request):
try:
request.user.auth_token.delete()
except (AttributeError, ObjectDoesNotExist):
pass
if getattr(settings, 'REST_SESSION_LOGIN', True):
django_logout(request)
response = Response({"detail": _("Successfully logged out.")},
status=status.HTTP_200_OK)
if getattr(settings, 'REST_USE_JWT', False):
from rest_framework_jwt.settings import api_settings as jwt_settings
if jwt_settings.JWT_AUTH_COOKIE:
response.delete_cookie(jwt_settings.JWT_AUTH_COOKIE)
# NOTE: this import occurs here rather than at the top level
# because JWT support is optional, and if `REST_USE_JWT` isn't
# True we shouldn't need the dependency
from rest_framework_simplejwt.exceptions import TokenError
from rest_framework_simplejwt.tokens import RefreshToken
cookie_name = getattr(settings, 'JWT_AUTH_COOKIE', None)
if cookie_name:
response.delete_cookie(cookie_name)
elif 'rest_framework_simplejwt.token_blacklist' in settings.INSTALLED_APPS:
# add refresh token to blacklist
try:
token = RefreshToken(request.data['refresh'])
token.blacklist()
except KeyError:
response = Response({"detail": _("Refresh token was not included in request data.")},
status=status.HTTP_401_UNAUTHORIZED)
except (TokenError, AttributeError, TypeError) as error:
if hasattr(error, 'args'):
if 'Token is blacklisted' in error.args or 'Token is invalid or expired' in error.args:
response = Response({"detail": _(error.args[0])},
status=status.HTTP_401_UNAUTHORIZED)
else:
response = Response({"detail": _("An error has occurred.")},
status=status.HTTP_500_INTERNAL_SERVER_ERROR)
else:
response = Response({"detail": _("An error has occurred.")},
status=status.HTTP_500_INTERNAL_SERVER_ERROR)
else:
response = Response({
"detail": _("Neither cookies or blacklist are enabled, so the token has not been deleted server "
"side. Please make sure the token is deleted client side."
)}, status=status.HTTP_200_OK)
return response
@ -162,7 +206,6 @@ class UserDetailsView(RetrieveUpdateAPIView):
"""
Adding this method since it is sometimes called when using
django-rest-swagger
https://github.com/Tivix/django-rest-auth/issues/275
"""
return get_user_model().objects.none()

View File

@ -85,17 +85,17 @@ qthelp:
@echo
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
".qhcp project file in $(BUILDDIR)/qthelp, like this:"
@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/django-rest-auth.qhcp"
@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/dj-rest-auth.qhcp"
@echo "To view the help file:"
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/django-rest-auth.qhc"
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/dj-rest-auth.qhc"
devhelp:
$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
@echo
@echo "Build finished."
@echo "To view the help file:"
@echo "# mkdir -p $$HOME/.local/share/devhelp/django-rest-auth"
@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/django-rest-auth"
@echo "# mkdir -p $$HOME/.local/share/devhelp/dj-rest-auth"
@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/dj-rest-auth"
@echo "# devhelp"
epub:

View File

@ -4,7 +4,7 @@ API endpoints
Basic
-----
- /rest-auth/login/ (POST)
- /dj-rest-auth/login/ (POST)
- username
- email
@ -12,24 +12,24 @@ Basic
Returns Token key
- /rest-auth/logout/ (POST)
- /dj-rest-auth/logout/ (POST)
.. note:: ``ACCOUNT_LOGOUT_ON_GET = True`` to allow logout using GET - this is the exact same configuration from allauth. NOT recommended, see: http://django-allauth.readthedocs.io/en/latest/views.html#logout
- /rest-auth/password/reset/ (POST)
- /dj-rest-auth/password/reset/ (POST)
- email
- /rest-auth/password/reset/confirm/ (POST)
- /dj-rest-auth/password/reset/confirm/ (POST)
- uid
- token
- new_password1
- new_password2
.. note:: uid and token are sent in email after calling /rest-auth/password/reset/
.. note:: uid and token are sent in email after calling /dj-rest-auth/password/reset/
- /rest-auth/password/change/ (POST)
- /dj-rest-auth/password/change/ (POST)
- new_password1
- new_password2
@ -38,7 +38,7 @@ Basic
.. note:: ``OLD_PASSWORD_FIELD_ENABLED = True`` to use old_password.
.. note:: ``LOGOUT_ON_PASSWORD_CHANGE = False`` to keep the user logged in after password change
- /rest-auth/user/ (GET, PUT, PATCH)
- /dj-rest-auth/user/ (GET, PUT, PATCH)
- username
- first_name
@ -50,31 +50,36 @@ Basic
Registration
------------
- /rest-auth/registration/ (POST)
- /dj-rest-auth/registration/ (POST)
- username
- password1
- password2
- email
- /rest-auth/registration/verify-email/ (POST)
- /dj-rest-auth/registration/verify-email/ (POST)
- key
.. note:: If you set account email verification as mandatory, you have to add the VerifyEmailView with the used `name`.
You need to import the view: ``from dj_rest_auth.registration.views import VerifyEmailView``. Then add the url with the corresponding name:
``path('dj-rest-auth/account-confirm-email/', VerifyEmailView.as_view(), name='account_email_verification_sent')`` to the urlpatterns list.
Social Media Authentication
---------------------------
Basing on example from installation section :doc:`Installation </installation>`
- /rest-auth/facebook/ (POST)
- /dj-rest-auth/facebook/ (POST)
- access_token
- code
.. note:: ``access_token`` OR ``code`` can be used as standalone arguments, see https://github.com/Tivix/django-rest-auth/blob/master/rest_auth/registration/views.py
.. note:: ``access_token`` OR ``code`` can be used as standalone arguments, see https://github.com/jazzband/dj-rest-auth/blob/master/dj_rest_auth/registration/views.py
- /rest-auth/twitter/ (POST)
- /dj-rest-auth/twitter/ (POST)
- access_token
- token_secret

View File

@ -1,120 +0,0 @@
Changelog
=========
0.9.5
-----
- fixed package distribution issue
0.9.4
-----
- Compatibility fixes (#437, #506)
- JWT auth cookie fix (#345)
- config & packaging fixes
- updated docs
- added new translations (Czech, Chinese, Turkish, Korean)
0.9.3
-----
- added social connect views
- added check for pre-existing accounts in social login
- prevent double-validation in LoginSerializer
- unit tests and demo project changes for Django 2.0
0.9.2
-----
- added permission classes configuration for registration
- added more info to JWT docs
- added Polish translations
0.9.1
-----
- fixed import error when extending rest_auth serializers
- added sensitive fields decorator
- added Spanish translations
0.9.0
-----
- allowed using custom UserDetailsSerializer with JWTSerializer
- fixed error with logout on GET
- updated api endpoints and configuration docs
- bugfixes
- minor text fixes
0.8.2
-----
- fixed allauth import error
- added swagger docs to demo project
0.8.1
-----
- added support for django-allauth hmac email confirmation pattern
0.8.0
-----
- added support for django-rest-framework-jwt
- bugfixes
0.7.0
-----
- Wrapped API returned strings in ugettext_lazy
- Fixed not using ``get_username`` which caused issues when using custom user model without username field
- Django 1.9 support
- Added ``TwitterLoginSerializer``
0.6.0
-----
- dropped support for Python 2.6
- dropped support for Django 1.6
- fixed demo code
- added better validation support for serializers
- added optional logout after password change
- compatibility fixes
- bugfixes
0.5.0
-----
- replaced request.DATA with request.data for compatibility with DRF 3.2
- authorization codes for social login
- view classes rename (appended "View" to all of them)
- bugfixes
0.4.0
-----
- Django 1.8 compatiblity fixes
0.3.4
-----
- fixed bug in PasswordResetConfirmation serializer (token field wasn't validated)
- fixed bug in Register view
0.3.3
-----
- support django-rest-framework v3.0
0.3.2
-----
- fixed few minor bugs
0.3.1
-----
- added old_password field in PasswordChangeSerializer
- make all endpoints browsable
- removed LoggedInRESTAPIView, LoggedOutRESTAPIView
- fixed minor bugs
0.3.0
-----
- replaced ``django-registration`` with ``django-allauth``
- moved registration logic to separated django application (``rest_auth.registration``)
- added serializers customization in django settings
- added social media authentication view
- changed request method from GET to POST in logout endpoint
- changed request method from POST to PUT/PATCH for user details edition
- changed password reset confim url - uid and token should be sent in POST
- increase test coverage
- made compatibile with django 1.7
- removed user profile support

View File

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
#
# django-rest-auth documentation build configuration file, created by
# dj-rest-auth documentation build configuration file, created by
# sphinx-quickstart on Wed Oct 8 15:59:37 2014.
#
# This file is execfile()d with the current directory set to its
@ -12,8 +12,12 @@
# All configuration values have a default; values that are commented out
# serve to show the default.
import sys
import os
import sys
about = {}
with open('../dj_rest_auth/__version__.py', 'r', encoding="utf8") as f:
exec(f.read(), about)
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
@ -43,17 +47,17 @@ source_suffix = '.rst'
master_doc = 'index'
# General information about the project.
project = u'django-rest-auth'
copyright = u'2018, Tivix Inc.'
project = u'dj-rest-auth'
copyright = u'2020, @iMerica'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = '0.9.5'
version = about['__version__']
# The full version, including alpha/beta/rc tags.
release = '0.9.5'
release = about['__version__']
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
@ -176,7 +180,7 @@ html_static_path = ['_static']
#html_file_suffix = None
# Output file base name for HTML help builder.
htmlhelp_basename = 'django-rest-authdoc'
htmlhelp_basename = 'dj-rest-authdoc'
# -- Options for LaTeX output ---------------------------------------------
@ -196,8 +200,8 @@ latex_elements = {
# (source start file, target name, title,
# author, documentclass [howto, manual, or own class]).
latex_documents = [
('index', 'django-rest-auth.tex', u'django-rest-auth Documentation',
u'Tivix Inc.', 'manual'),
('index', 'dj-rest-auth.tex', u'dj-rest-auth Documentation',
u'iMerica Inc.', 'manual'),
]
# The name of an image file (relative to this directory) to place at the top of
@ -226,8 +230,8 @@ latex_documents = [
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
('index', 'django-rest-auth', u'django-rest-auth Documentation',
[u'Tivix Inc.'], 1)
('index', 'dj-rest-auth', u'dj-rest-auth Documentation',
[u'@iMerica'], 1)
]
# If true, show URL addresses after external links.
@ -240,8 +244,8 @@ man_pages = [
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
('index', 'django-rest-auth', u'django-rest-auth Documentation',
u'Tivix Inc.', 'django-rest-auth', 'One line description of project.',
('index', 'dj-rest-auth', u'dj-rest-auth Documentation',
u'@iMerica', 'dj-rest-auth', 'One line description of project.',
'Miscellaneous'),
]

View File

@ -6,19 +6,19 @@ Configuration
You can define your custom serializers for each endpoint without overriding urls and views by adding ``REST_AUTH_SERIALIZERS`` dictionary in your django settings.
Possible key values:
- LOGIN_SERIALIZER - serializer class in ``rest_auth.views.LoginView``, default value ``rest_auth.serializers.LoginSerializer``
- LOGIN_SERIALIZER - serializer class in ``dj_rest_auth.views.LoginView``, default value ``dj_rest_auth.serializers.LoginSerializer``
- TOKEN_SERIALIZER - response for successful authentication in ``rest_auth.views.LoginView``, default value ``rest_auth.serializers.TokenSerializer``
- TOKEN_SERIALIZER - response for successful authentication in ``dj_rest_auth.views.LoginView``, default value ``dj_rest_auth.serializers.TokenSerializer``
- JWT_SERIALIZER - (Using REST_USE_JWT=True) response for successful authentication in ``rest_auth.views.LoginView``, default value ``rest_auth.serializers.JWTSerializer``
- JWT_SERIALIZER - (Using REST_USE_JWT=True) response for successful authentication in ``dj_rest_auth.views.LoginView``, default value ``dj_rest_auth.serializers.JWTSerializer``
- USER_DETAILS_SERIALIZER - serializer class in ``rest_auth.views.UserDetailsView``, default value ``rest_auth.serializers.UserDetailsSerializer``
- USER_DETAILS_SERIALIZER - serializer class in ``dj_rest_auth.views.UserDetailsView``, default value ``dj_rest_auth.serializers.UserDetailsSerializer``
- PASSWORD_RESET_SERIALIZER - serializer class in ``rest_auth.views.PasswordResetView``, default value ``rest_auth.serializers.PasswordResetSerializer``
- PASSWORD_RESET_SERIALIZER - serializer class in ``dj_rest_auth.views.PasswordResetView``, default value ``dj_rest_auth.serializers.PasswordResetSerializer``
- PASSWORD_RESET_CONFIRM_SERIALIZER - serializer class in ``rest_auth.views.PasswordResetConfirmView``, default value ``rest_auth.serializers.PasswordResetConfirmSerializer``
- PASSWORD_RESET_CONFIRM_SERIALIZER - serializer class in ``dj_rest_auth.views.PasswordResetConfirmView``, default value ``dj_rest_auth.serializers.PasswordResetConfirmSerializer``
- PASSWORD_CHANGE_SERIALIZER - serializer class in ``rest_auth.views.PasswordChangeView``, default value ``rest_auth.serializers.PasswordChangeSerializer``
- PASSWORD_CHANGE_SERIALIZER - serializer class in ``dj_rest_auth.views.PasswordChangeView``, default value ``dj_rest_auth.serializers.PasswordChangeSerializer``
Example configuration:
@ -36,18 +36,18 @@ Configuration
You can define your custom serializers for registration endpoint.
Possible key values:
- REGISTER_SERIALIZER - serializer class in ``rest_auth.registration.views.RegisterView``, default value ``rest_auth.registration.serializers.RegisterSerializer``
- REGISTER_SERIALIZER - serializer class in ``dj_rest_auth.registration.views.RegisterView``, default value ``dj_rest_auth.registration.serializers.RegisterSerializer``
.. note:: The custom REGISTER_SERIALIZER must define a ``def save(self, request)`` method that returns a user model instance
- **REST_AUTH_TOKEN_MODEL** - model class for tokens, default value ``rest_framework.authtoken.models``
- **REST_AUTH_TOKEN_MODEL** - path to model class for tokens, default value ``'rest_framework.authtoken.models.Token'``
- **REST_AUTH_TOKEN_CREATOR** - callable to create tokens, default value ``rest_auth.utils.default_create_token``.
- **REST_AUTH_TOKEN_CREATOR** - path to callable or callable for creating tokens, default value ``dj_rest_auth.utils.default_create_token``.
- **REST_SESSION_LOGIN** - Enable session login in Login API view (default: True)
- **REST_USE_JWT** - Enable JWT Authentication instead of Token/Session based. This is built on top of django-rest-framework-jwt http://getblimp.github.io/django-rest-framework-jwt/, which must also be installed. (default: False)
- **REST_USE_JWT** - Enable JWT Authentication instead of Token/Session based. This is built on top of djangorestframework-simplejwt https://github.com/SimpleJWT/django-rest-framework-simplejwt, which must also be installed. (default: False)
- **JWT_AUTH_COOKIE** - The cookie name/key.
- **OLD_PASSWORD_FIELD_ENABLED** - set it to True if you want to have old password verification on password change enpoint (default: False)
- **LOGOUT_ON_PASSWORD_CHANGE** - set to False if you want to keep the current user logged in after a password change

View File

@ -1,17 +1,28 @@
Demo project
============
The idea of creating demo project was to show how you can potentially use
django-rest-auth app with jQuery on frontend.
Do these steps to make it running (ideally in virtualenv).
This demo project shows how you can potentially use
dj-rest-auth app with jQuery on frontend.
To run this locally follow the steps below.
.. code-block:: python
cd /tmp
git clone https://github.com/Tivix/django-rest-auth.git
cd django-rest-auth/demo/
git clone https://github.com/jazzband/dj-rest-auth.git
cd dj-rest-auth/demo/
pip install -r requirements.pip
python manage.py migrate --settings=demo.settings --noinput
python manage.py runserver --settings=demo.settings
Now, go to ``http://127.0.0.1:8000/`` in your browser.
Now, go to ``http://127.0.0.1:8000/`` in your browser. There is also a
Single Page Application (SPA) in React within the ``demo/`` directory. To run this do:
.. code-block:: python
cd react-spa/
yarn # or npm install
yarn run start
Now, go to ``https://localhost:3000`` in your browser to view it.

15
docs/disclosure.rst Normal file
View File

@ -0,0 +1,15 @@
Vulnerability Disclosure Policy
===============================
Please observe the standard best practices of responsible disclosure, especially considering that this is OSS.
See OWASP's disclosure `cheat sheet <https://cheatsheetseries.owasp.org/cheatsheets/Vulnerability_Disclosure_Cheat_Sheet.html>`_.
Some basic rules:
- Keep it legal.
- Respect everyone's privacy.
- Contact the core maintainer(s) immediately if you discover a serious security vulnerability (imichael@pm.me for now).

View File

@ -3,7 +3,7 @@ FAQ
1. Why account_confirm_email url is defined but it is not usable?
In /rest_auth/registration/urls.py we can find something like this:
In /dj_rest_auth/registration/urls.py we can find something like this:
.. code-block:: python
@ -36,12 +36,12 @@ FAQ
# custom fields for user
company_name = models.CharField(max_length=100)
To allow update user details within one request send to rest_auth.views.UserDetailsView view, create serializer like this:
To allow update user details within one request send to dj_rest_auth.views.UserDetailsView view, create serializer like this:
.. code-block:: python
from rest_framework import serializers
from rest_auth.serializers import UserDetailsSerializer
from dj_rest_auth.serializers import UserDetailsSerializer
class UserSerializer(UserDetailsSerializer):

View File

@ -1,17 +1,17 @@
.. django-rest-auth documentation master file, created by
.. dj-rest-auth documentation master file, created by
sphinx-quickstart on Wed Oct 8 15:59:37 2014.
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
Welcome to django-rest-auth's documentation!
Welcome to dj-rest-auth's documentation!
============================================
.. warning:: Updating django-rest-auth from version **0.3.3** is highly recommended because of a security issue in PasswordResetConfirmation validation method.
.. note:: django-rest-auth from v0.3.3 supports django-rest-framework v3.0
.. note:: dj-rest-auth version 1.0.0 now uses Django Simple JWT.
|build-status| |coverage-status| |requirements-status| |docs|
.. image:: https://circleci.com/gh/jazzband/dj-rest-auth.svg?style=svg
:target: https://circleci.com/gh/jazzband/dj-rest-auth
Contents
--------
@ -25,28 +25,4 @@ Contents
Configuration <configuration>
Demo project <demo>
FAQ <faq>
Changelog <changelog>
.. |build-status| image:: https://travis-ci.org/Tivix/django-rest-auth.svg?branch=master
:alt: build status
:scale: 100%
:target: https://travis-ci.org/Tivix/django-rest-auth
.. |coverage-status| image:: https://coveralls.io/repos/Tivix/django-rest-auth/badge.png?branch=master
:alt: coverage status
:scale: 100%
:target: https://coveralls.io/r/Tivix/django-rest-auth?branch=master
.. |requirements-status| image:: https://requires.io/github/Tivix/django-rest-auth/requirements.png?branch=master
:alt: requirements status
:scale: 100%
:target: https://requires.io/github/Tivix/django-rest-auth/requirements/?branch=master
.. |docs| image:: https://readthedocs.org/projects/django-rest-auth/badge/?version=latest
:scale: 100%
:target: https://readthedocs.org/projects/django-rest-auth/?badge=latest
:alt: Documentation Status
Disclosure Policy <disclosure>

View File

@ -5,9 +5,9 @@ Installation
.. code-block:: python
pip install django-rest-auth
pip install dj-rest-auth
2. Add ``rest_auth`` app to INSTALLED_APPS in your django settings.py:
2. Add ``dj_rest_auth`` app to INSTALLED_APPS in your django settings.py:
.. code-block:: python
@ -16,19 +16,19 @@ Installation
'rest_framework',
'rest_framework.authtoken',
...,
'rest_auth'
'dj_rest_auth'
)
.. note:: This project depends on ``django-rest-framework`` library, so install it if you haven't done yet. Make sure also you have installed ``rest_framework`` and ``rest_framework.authtoken`` apps
3. Add rest_auth urls:
3. Add dj_rest_auth urls:
.. code-block:: python
urlpatterns = [
...,
url(r'^rest-auth/', include('rest_auth.urls'))
path('dj-rest-auth/', include('dj_rest_auth.urls'))
]
4. Migrate your database
@ -44,9 +44,9 @@ You're good to go now!
Registration (optional)
-----------------------
1. If you want to enable standard registration process you will need to install ``django-allauth`` by using ``pip install django-rest-auth[with_social]``.
1. If you want to enable standard registration process you will need to install ``django-allauth`` by using ``pip install 'dj-rest-auth[with_social]'``.
2. Add ``django.contrib.sites``, ``allauth``, ``allauth.account`` and ``rest_auth.registration`` apps to INSTALLED_APPS in your django settings.py:
2. Add ``django.contrib.sites``, ``allauth``, ``allauth.account`` and ``dj_rest_auth.registration`` apps to INSTALLED_APPS in your django settings.py:
3. Add ``SITE_ID = 1`` to your django settings.py
@ -57,26 +57,26 @@ Registration (optional)
'django.contrib.sites',
'allauth',
'allauth.account',
'rest_auth.registration',
'dj_rest_auth.registration',
)
SITE_ID = 1
3. Add rest_auth.registration urls:
3. Add dj_rest_auth.registration urls:
.. code-block:: python
urlpatterns = [
...,
url(r'^rest-auth/', include('rest_auth.urls')),
url(r'^rest-auth/registration/', include('rest_auth.registration.urls'))
path('dj-rest-auth/', include('dj_rest_auth.urls')),
path('dj-rest-auth/registration/', include('dj_rest_auth.registration.urls'))
]
Social Authentication (optional)
--------------------------------
Using ``django-allauth``, ``django-rest-auth`` provides helpful class for creating social media authentication view.
Using ``django-allauth``, ``dj-rest-auth`` provides helpful class for creating social media authentication view.
.. note:: Points 1 and 2 are related to ``django-allauth`` configuration, so if you have already configured social authentication, then please go to step 3. See ``django-allauth`` documentation for more details.
@ -88,12 +88,12 @@ Using ``django-allauth``, ``django-rest-auth`` provides helpful class for creati
...,
'rest_framework',
'rest_framework.authtoken',
'rest_auth'
'dj_rest_auth'
...,
'django.contrib.sites',
'allauth',
'allauth.account',
'rest_auth.registration',
'dj_rest_auth.registration',
...,
'allauth.socialaccount',
'allauth.socialaccount.providers.facebook',
@ -106,12 +106,12 @@ Using ``django-allauth``, ``django-rest-auth`` provides helpful class for creati
Facebook
########
3. Create new view as a subclass of ``rest_auth.registration.views.SocialLoginView`` with ``FacebookOAuth2Adapter`` adapter as an attribute:
3. Create new view as a subclass of ``dj_rest_auth.registration.views.SocialLoginView`` with ``FacebookOAuth2Adapter`` adapter as an attribute:
.. code-block:: python
from allauth.socialaccount.providers.facebook.views import FacebookOAuth2Adapter
from rest_auth.registration.views import SocialLoginView
from dj_rest_auth.registration.views import SocialLoginView
class FacebookLogin(SocialLoginView):
adapter_class = FacebookOAuth2Adapter
@ -122,7 +122,7 @@ Facebook
urlpatterns += [
...,
url(r'^rest-auth/facebook/$', FacebookLogin.as_view(), name='fb_login')
path('dj-rest-auth/facebook/', FacebookLogin.as_view(), name='fb_login')
]
@ -131,13 +131,13 @@ Twitter
If you are using Twitter for your social authentication, it is a bit different since Twitter uses OAuth 1.0.
3. Create new view as a subclass of ``rest_auth.registration.views.SocialLoginView`` with ``TwitterOAuthAdapter`` adapter and ``TwitterLoginSerializer`` as an attribute:
3. Create new view as a subclass of ``dj_rest_auth.registration.views.SocialLoginView`` with ``TwitterOAuthAdapter`` adapter and ``TwitterLoginSerializer`` as an attribute:
.. code-block:: python
from allauth.socialaccount.providers.twitter.views import TwitterOAuthAdapter
from rest_auth.registration.views import SocialLoginView
from rest_auth.social_serializers import TwitterLoginSerializer
from dj_rest_auth.registration.views import SocialLoginView
from dj_rest_auth.social_serializers import TwitterLoginSerializer
class TwitterLogin(SocialLoginView):
serializer_class = TwitterLoginSerializer
@ -149,7 +149,7 @@ If you are using Twitter for your social authentication, it is a bit different s
urlpatterns += [
...,
url(r'^rest-auth/twitter/$', TwitterLogin.as_view(), name='twitter_login')
path('dj-rest-auth/twitter/', TwitterLogin.as_view(), name='twitter_login')
]
.. note:: Starting from v0.21.0, django-allauth has dropped support for context processors. Check out http://django-allauth.readthedocs.org/en/latest/changelog.html#from-0-21-0 for more details.
@ -160,13 +160,13 @@ GitHub
If you are using GitHub for your social authentication, it uses code and not AccessToken directly.
3. Create new view as a subclass of ``rest_auth.views.SocialLoginView`` with ``GitHubOAuth2Adapter`` adapter, an ``OAuth2Client`` and a callback_url as attributes:
3. Create new view as a subclass of ``dj_rest_auth.views.SocialLoginView`` with ``GitHubOAuth2Adapter`` adapter, an ``OAuth2Client`` and a callback_url as attributes:
.. code-block:: python
from allauth.socialaccount.providers.github.views import GitHubOAuth2Adapter
from allauth.socialaccount.providers.oauth2.client import OAuth2Client
from rest_auth.registration.views import SocialLoginView
from dj_rest_auth.registration.views import SocialLoginView
class GithubLogin(SocialLoginView):
adapter_class = GitHubOAuth2Adapter
@ -179,7 +179,7 @@ If you are using GitHub for your social authentication, it uses code and not Acc
urlpatterns += [
...,
url(r'^rest-auth/github/$', GitHubLogin.as_view(), name='github_login')
path('dj-rest-auth/github/', GitHubLogin.as_view(), name='github_login')
]
Additional Social Connect Views
@ -193,8 +193,8 @@ If you want to allow connecting existing accounts in addition to login, you can
from allauth.socialaccount.providers.github.views import GitHubOAuth2Adapter
from allauth.socialaccount.providers.twitter.views import TwitterOAuthAdapter
from allauth.socialaccount.providers.oauth2.client import OAuth2Client
from rest_auth.registration.views import SocialConnectView
from rest_auth.social_serializers import TwitterConnectSerializer
from dj_rest_auth.registration.views import SocialConnectView
from dj_rest_auth.social_serializers import TwitterConnectSerializer
class FacebookConnect(SocialConnectView):
adapter_class = FacebookOAuth2Adapter
@ -215,28 +215,28 @@ In urls.py:
urlpatterns += [
...,
url(r'^rest-auth/facebook/connect/$', FacebookConnect.as_view(), name='fb_connect')
url(r'^rest-auth/twitter/connect/$', TwitterConnect.as_view(), name='twitter_connect')
url(r'^rest-auth/github/connect/$', GithubConnect.as_view(), name='github_connect')
path('dj-rest-auth/facebook/connect/', FacebookConnect.as_view(), name='fb_connect')
path('dj-rest-auth/twitter/connect/', TwitterConnect.as_view(), name='twitter_connect')
path('dj-rest-auth/github/connect/', GithubConnect.as_view(), name='github_connect')
]
You can also use the following views to check all social accounts attached to the current authenticated user and disconnect selected social accounts:
.. code-block:: python
from rest_auth.registration.views import (
from dj_rest_auth.registration.views import (
SocialAccountListView, SocialAccountDisconnectView
)
urlpatterns += [
...,
url(
r'^socialaccounts/$',
path(
'socialaccounts/',
SocialAccountListView.as_view(),
name='social_account_list'
),
url(
r'^socialaccounts/(?P<pk>\d+)/disconnect/$',
path(
'socialaccounts/<int:pk>/disconnect/',
SocialAccountDisconnectView.as_view(),
name='social_account_disconnect'
)
@ -246,15 +246,41 @@ You can also use the following views to check all social accounts attached to th
JSON Web Token (JWT) Support (optional)
---------------------------------------
By default ``django-rest-auth`` uses Django's Token-based authentication. If you want to use JWT authentication, follow these steps:
By default ``dj-rest-auth`` uses Django's Token-based authentication. If you want to use JWT authentication, follow these steps:
1. Install `djangorestframework-jwt <http://getblimp.github.io/django-rest-framework-jwt/>`_
- ``djangorestframework-jwt`` is currently the only supported JWT library.
2. The ``JWT_PAYLOAD_HANDLER`` and ``JWT_ENCODE_HANDLER`` settings are imported from the ``django-rest-framework-jwt`` settings object.
- Refer to `the library's documentation <http://getblimp.github.io/django-rest-framework-jwt/#additional-settings>`_ for information on using different encoders.
1. Install `djangorestframework-simplejwt <https://github.com/SimpleJWT/django-rest-framework-simplejwt/>`_
- ``djangorestframework-simplejwt`` is currently the only supported JWT library.
3. Add the following configuration value to your settings file to enable JWT authentication.
2. Add a simple_jwt auth configuration to the list of authentication classes.
.. code-block:: python
REST_FRAMEWORK = {
...
'DEFAULT_AUTHENTICATION_CLASSES': (
...
'dj_rest_auth.utils.JWTCookieAuthentication',
)
...
}
3. Add the following configuration value to your settings file to enable JWT authentication in dj-rest-auth.
.. code-block:: python
REST_USE_JWT = True
4. Declare what you want the cookie key to be called.
.. code-block:: python
JWT_AUTH_COOKIE = 'my-app-auth'
This example value above will cause dj-rest-auth to return a `Set-Cookie` header that looks like this:
.. code-block:: bash
Set-Cookie: my-app-auth=xxxxxxxxxxxxx; expires=Sat, 28 Mar 2020 18:59:00 GMT; HttpOnly; Max-Age=300; Path=/
``JWT_AUTH_COOKIE`` is also used while authenticating each request against protected views.

View File

@ -2,7 +2,7 @@ Introduction
============
Since the introduction of django-rest-framework, Django apps have been able to serve up app-level REST API endpoints. As a result, we saw a lot of instances where developers implemented their own REST registration API endpoints here and there, snippets, and so on. We aim to solve this demand by providing django-rest-auth, a set of REST API endpoints to handle User Registration and Authentication tasks. By having these API endpoints, your client apps such as AngularJS, iOS, Android, and others can communicate to your Django backend site independently via REST APIs for User Management. Of course, we'll add more API endpoints as we see the demand.
Since the introduction of django-rest-framework, Django apps have been able to serve up app-level REST API endpoints. As a result, we saw a lot of instances where developers implemented their own REST registration API endpoints here and there, snippets, and so on. We aim to solve this demand by providing dj-rest-auth, a set of REST API endpoints to handle User Registration and Authentication tasks. By having these API endpoints, your client apps such as AngularJS, iOS, Android, and others can communicate to your Django backend site independently via REST APIs for User Management. Of course, we'll add more API endpoints as we see the demand.
Features
--------
@ -18,14 +18,14 @@ Features
Apps structure
--------------
* ``rest_auth`` has basic auth functionality like login, logout, password reset and password change
* ``rest_auth.registration`` has logic related with registration and social media authentication
* ``dj_rest_auth`` has basic auth functionality like login, logout, password reset and password change
* ``dj_rest_auth.registration`` has logic related with registration and social media authentication
Angular app
-----------
- Tivix has also created angular module which uses API endpoints from this app - `angular-django-registration-auth <https://github.com/Tivix/angular-django-registration-auth>`_
- iMerica has also created angular module which uses API endpoints from this app - `angular-django-registration-auth <https://github.com/iMerica/angular-django-registration-auth>`_
Demo project

View File

@ -115,9 +115,9 @@ if "%1" == "qthelp" (
echo.
echo.Build finished; now you can run "qcollectiongenerator" with the ^
.qhcp project file in %BUILDDIR%/qthelp, like this:
echo.^> qcollectiongenerator %BUILDDIR%\qthelp\django-rest-auth.qhcp
echo.^> qcollectiongenerator %BUILDDIR%\qthelp\dj-rest-auth.qhcp
echo.To view the help file:
echo.^> assistant -collectionFile %BUILDDIR%\qthelp\django-rest-auth.ghc
echo.^> assistant -collectionFile %BUILDDIR%\qthelp\dj-rest-auth.ghc
goto end
)

View File

@ -1,51 +0,0 @@
from django.conf import settings
from rest_auth.serializers import (
TokenSerializer as DefaultTokenSerializer,
JWTSerializer as DefaultJWTSerializer,
UserDetailsSerializer as DefaultUserDetailsSerializer,
LoginSerializer as DefaultLoginSerializer,
PasswordResetSerializer as DefaultPasswordResetSerializer,
PasswordResetConfirmSerializer as DefaultPasswordResetConfirmSerializer,
PasswordChangeSerializer as DefaultPasswordChangeSerializer)
from .utils import import_callable, default_create_token
create_token = import_callable(
getattr(settings, 'REST_AUTH_TOKEN_CREATOR', default_create_token))
serializers = getattr(settings, 'REST_AUTH_SERIALIZERS', {})
TokenSerializer = import_callable(
serializers.get('TOKEN_SERIALIZER', DefaultTokenSerializer))
JWTSerializer = import_callable(
serializers.get('JWT_SERIALIZER', DefaultJWTSerializer))
UserDetailsSerializer = import_callable(
serializers.get('USER_DETAILS_SERIALIZER', DefaultUserDetailsSerializer)
)
LoginSerializer = import_callable(
serializers.get('LOGIN_SERIALIZER', DefaultLoginSerializer)
)
PasswordResetSerializer = import_callable(
serializers.get(
'PASSWORD_RESET_SERIALIZER',
DefaultPasswordResetSerializer
)
)
PasswordResetConfirmSerializer = import_callable(
serializers.get(
'PASSWORD_RESET_CONFIRM_SERIALIZER',
DefaultPasswordResetConfirmSerializer
)
)
PasswordChangeSerializer = import_callable(
serializers.get(
'PASSWORD_CHANGE_SERIALIZER',
DefaultPasswordChangeSerializer
)
)

Binary file not shown.

View File

@ -0,0 +1,107 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-05-10 12:48+0000\n"
"PO-Revision-Date: 2020-05-10 15:04+0200\n"
"Language: sv\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"Last-Translator: \n"
"Language-Team: \n"
"X-Generator: Poedit 2.2.4\n"
#: rest_auth/rest_auth/registration/serializers.py:67
msgid "View is not defined, pass it as a context variable"
msgstr "Vyn definieras inte, skicka den som en kontextvariabel"
#: rest_auth/rest_auth/registration/serializers.py:72
msgid "Define adapter_class in view"
msgstr "Definiera “adapter_class” i vyn"
#: rest_auth/rest_auth/registration/serializers.py:91
msgid "Define callback_url in view"
msgstr "Definiera “callback_url” i vyn"
#: rest_auth/rest_auth/registration/serializers.py:95
msgid "Define client_class in view"
msgstr "Definiera “client_class” i vyn"
#: rest_auth/rest_auth/registration/serializers.py:116
msgid "Incorrect input. access_token or code is required."
msgstr "Felaktig inmatning. access_token eller code krävs."
#: rest_auth/rest_auth/registration/serializers.py:125
msgid "Incorrect value"
msgstr "Felaktigt värde"
#: rest_auth/rest_auth/registration/serializers.py:139
msgid "User is already registered with this e-mail address."
msgstr "Användaren är redan registrerad med den här e-postadressen."
#: rest_auth/rest_auth/registration/serializers.py:185
msgid "A user is already registered with this e-mail address."
msgstr "En användare är redan registrerad med den här e-postadressen."
#: rest_auth/rest_auth/registration/serializers.py:193
msgid "The two password fields didn't match."
msgstr "De två lösenordsfälten matchade inte."
#: rest_auth/rest_auth/registration/views.py:51
msgid "Verification e-mail sent."
msgstr "Verifikationsmail har skickats."
#: rest_auth/rest_auth/registration/views.py:98
msgid "ok"
msgstr "ok"
#: rest_auth/rest_auth/serializers.py:33
msgid "Must include \"email\" and \"password\"."
msgstr "Måste inkludera “email” och “password”."
#: rest_auth/rest_auth/serializers.py:44
msgid "Must include \"username\" and \"password\"."
msgstr "Måste innehålla “username” och “password”."
#: rest_auth/rest_auth/serializers.py:57
msgid "Must include either \"username\" or \"email\" and \"password\"."
msgstr "Måste innehålla antingen “username” eller “email” och “password”."
#: rest_auth/rest_auth/serializers.py:98
msgid "User account is disabled."
msgstr "Användarkontot är avstängt."
#: rest_auth/rest_auth/serializers.py:101
msgid "Unable to log in with provided credentials."
msgstr "Det går inte att logga in med de angivna uppgifterna."
#: rest_auth/rest_auth/serializers.py:110
msgid "E-mail is not verified."
msgstr "E-post är inte verifierad."
#: rest_auth/rest_auth/serializers.py:259
msgid "Your old password was entered incorrectly. Please enter it again."
msgstr "Ditt gamla lösenord angavs felaktigt. Vänligen ange det igen."
#: rest_auth/rest_auth/views.py:137
msgid "Successfully logged out."
msgstr "Utloggad."
#: rest_auth/rest_auth/views.py:190
msgid "Password reset e-mail has been sent."
msgstr "E-post för återställning av lösenord har skickats."
#: rest_auth/rest_auth/views.py:216
msgid "Password has been reset with the new password."
msgstr "Lösenordet har återställts med det nya lösenordet."
#: rest_auth/rest_auth/views.py:238
msgid "New password has been saved."
msgstr "Nytt lösenord har sparats."

View File

@ -1,10 +0,0 @@
from django.conf import settings
from rest_framework.authtoken.models import Token as DefaultTokenModel
from .utils import import_callable
# Register your models here.
TokenModel = import_callable(
getattr(settings, 'REST_AUTH_TOKEN_MODEL', DefaultTokenModel))

View File

@ -1,30 +0,0 @@
# Moved in Django 1.8 from django to tests/auth_tests/urls.py
from django.conf.urls import url
from django.contrib.auth import views
from django.contrib.auth.decorators import login_required
from django.contrib.auth.urls import urlpatterns
# special urls for auth test cases
urlpatterns += [
url(r'^logout/custom_query/$', views.logout, dict(redirect_field_name='follow')),
url(r'^logout/next_page/$', views.logout, dict(next_page='/somewhere/')),
url(r'^logout/next_page/named/$', views.logout, dict(next_page='password_reset')),
url(r'^password_reset_from_email/$', views.password_reset, dict(from_email='staffmember@example.com')),
url(r'^password_reset/custom_redirect/$', views.password_reset, dict(post_reset_redirect='/custom/')),
url(r'^password_reset/custom_redirect/named/$', views.password_reset, dict(post_reset_redirect='password_reset')),
url(r'^password_reset/html_email_template/$', views.password_reset,
dict(html_email_template_name='registration/html_password_reset_email.html')),
url(r'^reset/custom/(?P<uidb64>[0-9A-Za-z_\-]+)/(?P<token>[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})/$',
views.password_reset_confirm,
dict(post_reset_redirect='/custom/')),
url(r'^reset/custom/named/(?P<uidb64>[0-9A-Za-z_\-]+)/(?P<token>[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})/$',
views.password_reset_confirm,
dict(post_reset_redirect='password_reset')),
url(r'^password_change/custom/$', views.password_change, dict(post_change_redirect='/custom/')),
url(r'^password_change/custom/named/$', views.password_change, dict(post_change_redirect='password_reset')),
url(r'^admin_password_reset/$', views.password_reset, dict(is_admin_site=True)),
url(r'^login_required/$', login_required(views.password_reset)),
url(r'^login_required_login_url/$', login_required(views.password_reset, login_url='/somewhere/')),
]

View File

@ -1,5 +0,0 @@
django-allauth>=0.25.0
responses>=0.3.0
flake8==2.4.0
djangorestframework-jwt>=1.7.2
djangorestframework>=3.6.4

View File

@ -1,29 +0,0 @@
from six import string_types
from importlib import import_module
def import_callable(path_or_callable):
if hasattr(path_or_callable, '__call__'):
return path_or_callable
else:
assert isinstance(path_or_callable, string_types)
package, attr = path_or_callable.rsplit('.', 1)
return getattr(import_module(package), attr)
def default_create_token(token_model, user, serializer):
token, _ = token_model.objects.get_or_create(user=user)
return token
def jwt_encode(user):
try:
from rest_framework_jwt.settings import api_settings
except ImportError:
raise ImportError("djangorestframework_jwt needs to be installed")
jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER
payload = jwt_payload_handler(user)
return jwt_encode_handler(payload)

Some files were not shown because too many files have changed in this diff Show More