在运行时更新主体的字段

Posted

技术标签:

【中文标题】在运行时更新主体的字段【英文标题】:Update fields of the principal at the runtime 【发布时间】:2020-01-30 07:51:03 【问题描述】:

我在 Spring Boot 中将 OAuth2 身份验证与我自己的授权和资源服务器一起使用。我想在运行时代表同一用户或代表另一个用户(管理员/版主)更改我的User implements UserDetails(这是我的Principal)对象中的一些字段。例如。 user1 id=1 想换个国家,所以调用了这个方法:

@PostMapping("/setMyCountry")
public void setMyCountry(@CurrentUser User user, @RequestParam String newCountry)
    user.setCountry(newCountry);
    userRepository.save(user);

但是当我想用这个检查他的国家时:

@GetMapping("/getMyCountry")
public String getMyCountry(@CurrentUser User user)
    return user.getCountry();

我得到了同样古老的国家。

同样,以管理员身份进行更改:

@PostMapping("/setUserCountry")
public void setUserCountry(@CurrentUser Moderator moderator, @RequestParam String newCountry)
    User user = userRepository.findById(1L).get();
    user.setCountry(newCountry);
    userRepository.save(user);


@GetMapping("/getUserCountry")
public String getUserCountry(@CurrentUser Moderator moderator)
    User user = userRepository.findById(1L).get();
    return user.getCountry();

返回同一个国家。但是,当然,数据库显示出新的价值。

我已经看到关于类似问题的问题,但如果我在setMyCountry() 中使用它:

Authentication newAuth = new UsernamePasswordAuthenticationToken(user, user.getPassword(), user.getAuthorities());
SecurityContextHolder.getContext().setAuthentication(newAuth);

那么这仍然不起作用。请注意,我使用了我的自定义令牌、令牌提供者和令牌授予者,但它们最后都返回 UsernamePasswordAuthenticationToken

那么,如何在不注销和登录的情况下更改User 的字段并更新当前主体?

【问题讨论】:

用户主体不应是用户对象。通常的做法是 UserDetails 对象包含有关用户的授权详细信息。什么角色等等,而不是名字、姓氏地址和国家等个人信息。这就是数据库中的用户对象的用途。 UserPrincipal 可能包含一个 userId 以对用户进行数据库查找 @ThomasAndolf 谢谢,您能否分享一个链接,其中包含您所谈论的示例?我想看看实现细节。 实施细节?您的 jwt 中有一个 id,然后将其转换为您的自定义 userdetails 对象。此 id 是您可以用来在数据库中查找 userId 对象的 id。 @ThomasAndolf 我问是因为我并不完全清楚你的意思。您的意思是我的数据库中需要两个表:使用我的自定义UserDetails(用户名,密码)和UserInformation/User(aboutMe,国家等)?或者我可以保存我当前的数据库方案,所以我只需要 User 表(带有 id、用户名、密码,还带有所有其他信息,例如 aboutMe、国家等),但 Spring 中有两个类:@987654335 @ 和 User 实体?请从这个角度添加更多细节。 你在做什么登录流程?会议? Oauth2? jwt? 【参考方案1】:

使用 oauth2 时的常见做法是,身份验证服务器对用户一无所知,只知道用户名、密码、角色和某种密钥,因此它可以查找用户对象。这可以是唯一的 UUID,也可以是电子邮件地址中的用户名(主题)。

资源服务器从客户端获取一个令牌,它获取这个令牌,然后调用授权服务器来验证令牌,授权服务器验证它,如果验证通过,然后将信息发送回资源​​服务器,以便资源服务器可以填充其 UserDetails 对象。

如果资源服务器需要知道这个用户住在哪个国家,它会从 Principal/UserDetails 对象中获取 id,然后调用用户服务,或者另一个数据库,或者另一个表,甚至返回授权服务器可能具有 /user 端点并将令牌提供给授权服务器(依次获取主体信息,获取主题,然后在数据库中查找用户信息),然后将用户对象发回。

我的意思是,您应该始终将身份验证和授权(角色等)信息与实际用户信息分开。

如果您从使用 facebook 身份验证更改为 github 身份验证会怎样。您需要重做所有用户吗?不,因为您将所有用户信息与授权信息分开。

【讨论】:

谢谢!但是如果我使用自己的授权和资源服务器,那么只使用一个Users 表,但是Spring 中的两个类:CustomUserDetails implements UserDetailsUser 实体是否可以? 正如我所说,我已经指出了很多很多次。这是不好的做法,即使你拥有或不拥有两者。仅仅因为你可以,并不意味着它是好的。

以上是关于在运行时更新主体的字段的主要内容,如果未能解决你的问题,请参考以下文章

在运行时更新悖论表

在mongodb中保存或更新文档时如何防止更新“updatedAt”字段?

当我运行迁移时,uuid 字段总是在更新,它会给我一些性能问题,任何人都可以向我解释原因和解决方案

在运行时更新 label.text

126 - 处决 06

更新 mongodb 文档时删除的字段