Django OAuthToolkit:如何为视图设置不同的读写权限范围?
我来帮你搞定这个权限范围的配置问题,其实TokenHasResourceScope本身就设计了支持读写拆分的逻辑,只是需要正确理解它的工作方式并完成对应配置,下面分两种方案说明:
方案1:利用TokenHasResourceScope的默认逻辑(推荐)
TokenHasResourceScope的核心逻辑就是根据请求方法自动区分读写scope:
- 对于SAFE方法(GET/HEAD/OPTIONS),它会自动在你设置的
required_scopes每个值后面追加:read,然后检查令牌是否包含这个组合后的scope(比如你设置required_scopes=['user_detail'],GET请求就需要user_detail:read) - 对于UNSAFE方法(PUT/PATCH/DELETE),则会追加
:write,检查user_detail:write
你现在遇到的invalid scope问题,大概率是两个原因:
a) 未在OAuth2服务器注册读写scope
你需要先在Django后台的OAuth2 Provider -> Scopes页面,手动添加user_detail:read和user_detail:write这两个scope(也可以通过代码批量注册)。只有注册过的scope,客户端才能合法申请,令牌才会包含这些有效范围。
b) 客户端未申请正确的scope
当客户端获取令牌时,需要明确指定对应的scope:比如只读请求就传scope=user_detail:read,修改请求传scope=user_detail:write,需要同时读写就传scope=user_detail:read user_detail:write。如果客户端之前只申请了user_detail这个基础scope,令牌里自然不会有带后缀的读写scope,也就会返回权限错误。
方案2:自定义权限类(适用于更灵活的场景)
如果需要更精细的控制(比如读写用完全独立的基础scope,而不是同一个scope加后缀),可以自定义一个继承自TokenHasResourceScope的权限类,根据请求方法动态返回需要的scope:
from oauth2_provider.contrib.rest_framework import TokenHasResourceScope class TokenHasReadWriteResourceScope(TokenHasResourceScope): def get_required_scopes(self, request, view): # 根据请求方法判断所需scope if request.method in self.safe_methods: # SAFE方法返回read类scope return ["user_detail:read"] # 这里可以直接写固定scope,或者根据view的参数生成 else: # UNSAFE方法返回write类scope return ["user_detail:write"]
然后在视图中替换权限类:
class UserDetailView(RetrieveUpdateDestroyAPIView): serializer_class = UserUpdateSerializer permission_classes = [TokenHasReadWriteResourceScope] # 这里可以不用required_scopes,直接在自定义权限类里写死,或者保留用于动态生成
这种方式的好处是你可以完全自定义读写对应的scope,比如把read的scope改成user_profile_read,write的改成user_profile_edit,完全不受默认后缀的限制。
额外注意事项
- 如果需要让某个用户同时拥有读写权限,只需要让他们的令牌同时包含
user_detail:read和user_detail:write两个scope - 检查你的OAuth2应用配置,确保应用的
Allowed Scopes列表里包含了你定义的读写scope,否则客户端无法申请这些范围
内容的提问来源于stack exchange,提问作者Praful Bagai

