下面是Django实现CAS+OAuth2的方法示例的详细攻略。
简介
首先,我们需要了解一下CAS和OAuth2的概念。CAS(Central Authentication Service)是一种单点登录协议,可以让用户在一个网站上进行登录之后,在其他网站上自动登录,避免用户重复输入用户名和密码。OAuth2是一种授权协议,允许第三方应用程序通过授权代表用户访问受保护的资源。
本文将介绍如何在Django中实现CAS+OAuth2的功能,以实现单点登录和跨应用程序授权访问的需求。
实现
准备工作
首先,我们需要安装必要的包。
pip install django-cas-ng oauthlib requests requests-oauthlib
配置CAS
在settings.py
中添加如下配置:
INSTALLED_APPS = [
# ...
'django_cas_ng',
]
# CAS 配置
AUTHENTICATION_BACKENDS = [
'django_cas_ng.backends.CASBackend',
'django.contrib.auth.backends.ModelBackend',
]
MIDDLEWARE = [
# ...
'django_cas_ng.middleware.CASMiddleware',
]
# CAS 参数配置
CAS_SERVER_URL = 'https://example.com/cas/'
CAS_ADMIN_PREFIX = 'admin/'
# 开启 CAS 单点登录支持
CAS_SINGLE_SIGN_OUT = True
CAS_LOGGED_MSG = "[CAS: {user}][APP: {app}][IP: {ip}] login success"
CAS_LOGGED_OUT_MSG = "[CAS: {user}][APP: {app}][IP: {ip}] logout success"
配置OAuth2
在settings.py
中添加如下配置:
AUTHENTICATION_BACKENDS += ['oauth2_provider.backends.OAuth2Backend']
REST_FRAMEWORK = {
# ...
'DEFAULT_AUTHENTICATION_CLASSES': (
'oauth2_provider.contrib.rest_framework.OAuth2Authentication',
),
}
实现CAS用户同步
在models.py
中实现CAS用户同步:
from django.contrib.auth.models import AbstractUser
from django.db import models
from django_cas_ng.signals import cas_user_authenticated
class User(AbstractUser):
is_cas_user = models.BooleanField('CAS 用户', default=False)
# ...
def cas_user_authenticated_handler(sender, user, **kwargs):
"""
当 CAS 用户登录成功时,同步用户信息到本地数据库中
"""
if user:
cas_username = kwargs.get('attributes', {}).get('uid', '')
if not cas_username:
cas_username = user.username
u, _ = User.objects.update_or_create(
username=cas_username,
defaults={
'is_cas_user': True,
'first_name': kwargs.get('attributes', {}).get('firstName', ''),
'last_name': kwargs.get('attributes', {}).get('lastName', ''),
'email': kwargs.get('attributes', {}).get('email', ''),
'is_staff': True,
'is_active': True,
}
)
cas_user_authenticated.connect(cas_user_authenticated_handler)
实现OAuth2授权
在views.py
中实现OAuth2授权:
from django.http import JsonResponse
from oauth2_provider.models import AccessToken
from oauthlib.oauth2 import BackendApplicationClient
from requests_oauthlib import OAuth2Session
def oauth2_authorize(request):
client_id = 'your_client_id'
client_secret = 'your_client_secret'
auth_url = 'https://example.com/o/authorize/'
token_url = 'https://example.com/o/token/'
# 申请 access_token
client = BackendApplicationClient(client_id=client_id)
oauth = OAuth2Session(client=client)
token = oauth.fetch_token(
token_url=token_url,
client_id=client_id,
client_secret=client_secret,
)
# 获取 access_token
token = AccessToken.objects.create(
user=request.user,
token=token['access_token'],
application_id=client_id,
expires=token['expires_in'],
scope=token.get('scope', ''),
)
return JsonResponse({'access_token': token.token})
实现跨应用程序授权
在settings.py
中添加如下配置:
OAUTH2_PROVIDER = {
# ...
'SCOPES': {
'read': 'Read scope',
'write': 'Write scope',
},
}
在views.py
中实现跨应用程序授权:
from django.views.decorators.csrf import csrf_exempt
from oauth2_provider.decorators import protected_resource
from oauth2_provider.models import Application, get_access_token_model
from oauthlib.oauth2 import BackendApplicationClient
from requests_oauthlib import OAuth2Session
@csrf_exempt
@protected_resource()
def oauth2_resource(request):
access_token = get_access_token_model().objects\
.filter(token=request.META.get('HTTP_AUTHORIZATION', '').split()[1],
expires__gt=timezone.now())\
.first()
if not access_token:
return JsonResponse({'error': 'Access token invalid or expired.'}, status=401)
client_id = access_token.application.client_id
client_secret = access_token.application.client_secret
target_app_id = request.GET.get('target_app_id')
if not target_app_id:
return JsonResponse({'error': 'Target app not specified.'}, status=400)
target_app = Application.objects.filter(client_id=target_app_id).first()
if not target_app:
return JsonResponse({'error': 'Target app not found.'}, status=404)
# 申请 access_token
client = BackendApplicationClient(client_id=client_id)
oauth = OAuth2Session(client=client)
token = oauth.fetch_token(
token_url=target_app.token_url,
client_id=client_id,
client_secret=client_secret,
)
return JsonResponse({'access_token': token['access_token'], 'expires_in': token['expires_in']})
示例1:单点登录
一个公司中可能有多个系统,比如OA系统、CRM系统等等,每个系统都有自己的登录页面,如果用户想要使用这些系统,需要在每个系统中单独登录。如果实现单点登录,用户只需在一个系统中登录一次,然后就可以在其他系统中自动登录,这样会极大地方便用户的登录操作。
下面是实现单点登录的示例代码:
<!DOCTYPE html>
<html>
<head>
<title>登录页</title>
</head>
<body>
<form method="POST" action="{% url 'cas_ng_login' %}">
{% csrf_token %}
<label for="username">Username:</label>
<input type="text" name="username" required>
<br>
<label for="password">Password:</label>
<input type="password" name="password" required>
<br>
<input type="submit" value="Login">
</form>
</body>
</html>
上面的示例代码是一个简单的登录页,通过向{/cas/login}
地址提交表单,就可以完成CAS的登录验证,实现单点登录。
示例2:跨应用授权
在一些特定的场景下,需要实现不同应用之间的授权访问,比如在OA系统中访问CRM系统的客户信息,这时候就需要实现跨应用的授权。
下面是实现跨应用授权的示例代码:
import requests
# 获取 access_token
headers = {'Authorization': 'Bearer xxxxxx'}
response = requests.post('http://example.com/oauth2/resource?target_app_id=crm', headers=headers)
access_token = response.json().get('access_token', '')
# 使用 access_token 访问受保护的资源
headers = {'Authorization': 'Bearer ' + access_token}
response = requests.get('http://crm.example.com/api/customers/', headers=headers)
customers = response.json()
上面的示例代码中,首先通过/oauth2/resource
接口申请了一个具有crm
应用程序权限的access_token
,然后使用这个access_token
访问了受保护的资源。这样就实现了跨应用的授权访问。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Django实现CAS+OAuth2的方法示例 - Python技术站