在运行时更新主体的字段
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 UserDetails
和User
实体是否可以?
正如我所说,我已经指出了很多很多次。这是不好的做法,即使你拥有或不拥有两者。仅仅因为你可以,并不意味着它是好的。以上是关于在运行时更新主体的字段的主要内容,如果未能解决你的问题,请参考以下文章
在mongodb中保存或更新文档时如何防止更新“updatedAt”字段?