Django技术问题:如何根据微软账户类型获取对应模型的令牌?
问题:根据用户账户类型正确匹配Microsoft Graph令牌模型
问题背景
我在Django项目中集成了Microsoft Graph API,登录成功后将微软企业账户的access_token和refresh_token存储至ModelA,个人账户的令牌存储至ModelB。需求是根据用户的账户类型(企业/个人),调用对应模型的令牌——企业账户使用ModelA的令牌,个人账户使用ModelB的令牌。
但当前实现逻辑存在问题:当两个模型中都存在令牌数据时,总是优先调用先查询的ModelA,无法根据实际用户类型切换到对应模型;仅当其中一个模型无数据时才能正常工作。
模型定义
ModelA(企业账户令牌存储)
class ModelA(models.Model): active = models.BooleanField(null=True, blank=True) for_user = models.ForeignKey(ModelX, null=True, blank=True, on_delete=models.CASCADE) for_firm = models.ForeignKey(ModelMain, related_name="microsoft_for_firm", null=True, blank=True, on_delete=models.CASCADE) access_token = models.TextField(null=True, blank=True) refresh_token = models.TextField(null=True, blank=True)
ModelB(个人账户令牌存储)
class ModelB(models.Model): active = models.BooleanField(null=True, blank=True) for_user = models.ForeignKey(ModelX, null=True, blank=True, on_delete=models.CASCADE) for_firm = models.ForeignKey(ModelMain, related_name="microsoft_for_personal", null=True, blank=True, on_delete=models.CASCADE) access_token = models.TextField(null=True, blank=True) refresh_token = models.TextField(null=True, blank=True)
当前错误实现代码
refresh_token = None access_token = None userprofile = None try: profile = ModelF.objects.get(user=request.user, account_type='Attorney') userprofile = ModelMain.objects.get(attorneyprofile=profile) except: userprofile = ModelX.objects.get(user=request.user, account_type='AttorneyStaff') userprofile = userprofile.created_by org_refresh_token = ModelA.objects.filter(for_firm=userprofile, refresh_token__startswith='0.AU').first() if org_refresh_token: access_token = org_refresh_token.access_token print("\n Access Token :", access_token) user_type = get_user_type(access_token) print("\n User type in get refresh token :", user_type) if user_type == 'Member' and org_refresh_token.refresh_token.startswith("0.AU"): print("\n Member found \n") refresh_token = org_refresh_token.refresh_token print("\n REFRESH TOKEN Organisation :", refresh_token) else: per_refresh_token = ModelB.objects.filter(for_firm=userprofile, refresh_token__startswith='M.R3').first() if per_refresh_token: refresh_token = per_refresh_token.refresh_token print("\n REFRESH TOKEN Personal:", refresh_token) else: per_refresh_token = ModelB.objects.filter(for_firm=userprofile, refresh_token__startswith='M.R3').first() refresh_token = per_refresh_token.refresh_token print("\n REFRESH TOKEN Organisation:", refresh_token)
问题分析
当前代码的核心错误是逻辑顺序倒置:它先查询企业令牌(ModelA),再根据令牌的user_type决定是否切换到个人令牌(ModelB),而非先明确用户的目标账户类型,再定向查询对应模型的令牌。这种逻辑导致当两个模型都有数据时,始终优先使用ModelA,完全忽略用户的实际账户类型需求。
修复方案
我们需要先明确用户的目标账户类型(企业/个人),再直接到对应模型查询有效令牌。以下是调整后的实现:
1. 定义获取用户目标账户类型的函数
根据你的业务逻辑实现,比如从用户的profile、session或系统设置中读取用户选择的账户类型:
def get_target_microsoft_account_type(request): # 示例:从用户session获取临时选择的账户类型,默认企业 return request.session.get('selected_microsoft_account', 'enterprise') # 若用户profile有固定设置,可替换为: # return request.user.microsoft_profile.account_type
2. 调整令牌获取逻辑
refresh_token = None access_token = None userprofile = None # 保留原逻辑:获取用户对应的企业/机构信息 try: profile = ModelF.objects.get(user=request.user, account_type='Attorney') userprofile = ModelMain.objects.get(attorneyprofile=profile) except ModelF.DoesNotExist: userprofile = ModelX.objects.get(user=request.user, account_type='AttorneyStaff') userprofile = userprofile.created_by # 第一步:明确用户需要的账户类型 target_account_type = get_target_microsoft_account_type(request) # 第二步:根据目标类型定向查询对应模型的令牌 if target_account_type == 'enterprise': # 企业账户:查询ModelA,匹配企业令牌格式 token_obj = ModelA.objects.filter(for_firm=userprofile, refresh_token__startswith='0.AU').first() if token_obj: access_token = token_obj.access_token refresh_token = token_obj.refresh_token print("\n 已获取企业账户令牌") else: # 个人账户:查询ModelB,匹配个人令牌格式 token_obj = ModelB.objects.filter(for_firm=userprofile, refresh_token__startswith='M.R3').first() if token_obj: access_token = token_obj.access_token refresh_token = token_obj.refresh_token print("\n 已获取个人账户令牌") # 容错处理:未找到对应类型的令牌 if not refresh_token: print(f"\n 未找到{target_account_type}类型的有效令牌,请绑定对应微软账户")
3. 可选:基于令牌类型的校验(若需确保令牌类型与目标一致)
如果需要验证令牌的实际类型是否符合目标(防止令牌格式错误),可以添加校验逻辑:
def get_valid_token_by_type(userprofile, target_type): if target_type == 'enterprise': token_obj = ModelA.objects.filter(for_firm=userprofile, refresh_token__startswith='0.AU').first() if token_obj: # 验证令牌的用户类型是否为企业成员 user_type = get_user_type(token_obj.access_token) if user_type == 'Member': return token_obj.access_token, token_obj.refresh_token else: token_obj = ModelB.objects.filter(for_firm=userprofile, refresh_token__startswith='M.R3').first() if token_obj: # 可添加个人账户令牌的校验逻辑 return token_obj.access_token, token_obj.refresh_token return None, None # 使用方式 access_token, refresh_token = get_valid_token_by_type(userprofile, target_account_type)
关键优化点
- 逻辑前置:先确定用户的账户类型需求,再定向查询对应模型,彻底解决优先使用某一模型的问题。
- 逻辑解耦:将账户类型判断与令牌查询分离,代码更清晰,便于后续维护。
- 容错增强:添加无令牌时的提示,提升用户体验。
内容的提问来源于stack exchange,提问作者djangodeveloper
相关产品推荐
相关产品推荐

