You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于DRF微服务架构:跨项目访问用户模型及CAS实现咨询

解决方案:为DRF微服务搭建中央认证系统(CAS)

既然你已经有了基于OAuth2的users认证服务,我们可以直接把它扩展为中央认证核心,让products服务通过标准化的API交互获取用户信息——这才是微服务架构里的正确姿势,而非直接跨服务访问数据库模型。下面是适配你现有环境的具体实现步骤:

1. 优化Users服务作为CAS核心

首先要确保users服务不仅能处理登录认证,还能安全提供用户信息接口,并配置为OAuth2资源服务器验证其他服务的请求合法性。

1.1 配置OAuth2资源服务器

在users项目的settings.py中补充资源服务器相关配置:

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': [
        'oauth2_provider.contrib.rest_framework.OAuth2Authentication',
        'rest_framework.authentication.SessionAuthentication',
    ],
    'DEFAULT_PERMISSION_CLASSES': [
        'rest_framework.permissions.IsAuthenticated',
    ]
}

OAUTH2_PROVIDER = {
    'ACCESS_TOKEN_EXPIRE_SECONDS': 3600,  # 按需调整token过期时间
    'AUTHORIZATION_CODE_EXPIRE_SECONDS': 600,
    'SCOPES': {'read': 'Read scope', 'openid': 'User info scope'},
    'ALLOWED_REDIRECT_URI_LIST': ['http://localhost:8001/callback'],  # 添加products服务的回调地址
}

1.2 暴露标准化用户信息API

在users项目中新增视图,返回当前认证用户的核心信息:

# users/views.py
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.permissions import IsAuthenticated
from django.contrib.auth.models import User

class UserInfoView(APIView):
    permission_classes = [IsAuthenticated]

    def get(self, request):
        user = request.user
        return Response({
            'id': user.id,
            'username': user.username,
            'email': user.email,
            # 按需添加其他需要共享的用户字段
        })

然后在urls.py中注册这个接口:

# users/urls.py
from django.urls import path
from .views import UserInfoView

urlpatterns = [
    # 已有的OAuth2路由(比如/login、/o/token/等)...
    path('auth/user-info/', UserInfoView.as_view(), name='user-info'),
]

2. 配置Products服务作为OAuth2客户端

让products服务通过OAuth2客户端模式(适合服务间后台调用)获取access token,再用token调用users服务的用户信息接口。

2.1 安装依赖

在products项目中安装OAuth2相关工具:

pip install requests django-oauth-toolkit

2.2 添加客户端配置

在products项目的settings.py中添加OAuth2客户端的连接信息:

# products/settings.py
OAUTH2_CLIENT = {
    'CLIENT_ID': '你的users服务OAuth2客户端ID',  # 在users服务的Django后台创建OAuth2应用时生成的ID
    'CLIENT_SECRET': '你的users服务OAuth2客户端密钥',  # 对应应用的密钥
    'TOKEN_URL': 'http://localhost:8000/o/token/',
    'USER_INFO_URL': 'http://localhost:8000/auth/user-info/',
}

2.3 实现用户信息获取工具

创建工具函数封装token获取和用户信息请求逻辑:

# products/utils.py
import requests
from django.conf import settings
from django.core.cache import cache

def get_access_token():
    # 先从缓存取token,避免重复请求
    token = cache.get('oauth2_access_token')
    if token:
        return token
    
    # 客户端模式获取新token
    data = {
        'grant_type': 'client_credentials',
        'client_id': settings.OAUTH2_CLIENT['CLIENT_ID'],
        'client_secret': settings.OAUTH2_CLIENT['CLIENT_SECRET'],
        'scope': 'read',
    }
    response = requests.post(settings.OAUTH2_CLIENT['TOKEN_URL'], data=data)
    if response.status_code == 200:
        token_data = response.json()
        # 缓存token直到过期
        cache.set('oauth2_access_token', token_data['access_token'], token_data['expires_in'] - 60)
        return token_data['access_token']
    return None

def get_user_info(access_token):
    headers = {'Authorization': f'Bearer {access_token}'}
    response = requests.get(settings.OAUTH2_CLIENT['USER_INFO_URL'], headers=headers)
    if response.status_code == 200:
        return response.json()
    return None

2.4 在Products业务视图中使用用户信息

比如在你的getProduct视图中,需要关联用户信息时调用上述工具:

# products/views.py
from rest_framework.views import APIView
from rest_framework.response import Response
from .utils import get_access_token, get_user_info

class GetProductView(APIView):
    def get(self, request, product_id):
        # 获取服务间调用的access token
        service_token = get_access_token()
        if not service_token:
            return Response({'error': '认证服务连接失败'}, status=500)
        
        # 如果需要验证当前请求的用户,从请求头拿前端传来的用户token
        user_token = request.headers.get('Authorization', '').split(' ')[-1]
        user_info = get_user_info(user_token)
        
        # 处理产品业务逻辑,比如关联用户ID
        product_data = {
            'id': product_id,
            'name': '示例产品',
            'creator_id': user_info.get('id') if user_info else None
        }
        return Response(product_data)

3. 关键注意事项

  • 跨域配置:在users服务中允许products服务的跨域请求,安装django-cors-headers并配置:
    # users/settings.py
    INSTALLED_APPS = [
        # ...
        'corsheaders',
    ]
    MIDDLEWARE = [
        'corsheaders.middleware.CorsMiddleware',
        'django.middleware.common.CommonMiddleware',
        # ...
    ]
    CORS_ALLOWED_ORIGINS = [
        "http://localhost:8001",
    ]
    
  • 安全强化:生产环境必须使用HTTPS传输token;限制OAuth2客户端的权限范围(比如只给read权限);定期轮换客户端密钥。
  • 容错处理:在products服务中添加token获取失败的降级逻辑,避免认证服务不可用时导致产品服务完全瘫痪。

4. 测试验证

  1. 启动users和products服务
  2. 调用products的/products/getProduct/1接口,检查是否能正确获取并返回关联的用户信息
  3. 测试token过期后,工具函数是否能自动重新获取有效token

内容的提问来源于stack exchange,提问作者Mohammed Sameer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 08:00:04