上周,我开始扩展UserDetails类,以便能够支持自定义字段。关于这个领域的特殊之处在于它填充了一个取决于请求参数的值。我设法正确地实现了这个(所以问题不关注那个)。
现在的问题是,在成功登录后,UserDetails对象被正确填充(我能够使用AuthenticationSuccessHandler看到它),并且客户端从OAuth2提供程序接收JWT令牌。然后,客户端通过访问" / uaa / user"来尝试获取有关用户的更多详细信息。端点。这被设置为返回Principal对象。但在检查Principal对象的内容后,我被告知UserDetails对象丢失了。 getPrincipal()方法只返回用户名而不是UserDetails对象。
根据this question,这是登录失败的结果。 AuthenticationToken(在本例中为UsernamePasswordAuthenticationToken)被AuthenticationManager拒绝。我不知道它为什么要做这样的事情。使用默认UserDetails对象的身份验证似乎工作得很好。有人可以帮我解决这个问题吗?
有关已实施类的一些细节(如上所述)。有些代码因此被遗漏。
CustomUserDetails
public class CustomUserDetails extends User {
private final Integer custom;
public CustomUserDetails (...default params..., Integer custom) {
super(...default params...);
this.custom = custom;
}
}
CustomUserDetailsService
@Service
public class CustomUserDetailsService implements UserDetailsService {
@Override
public CustomUserDetails loadUserByUsername(String username) throw UsernameNotFoundException {
return new CustomUserDetails(...default params..., 12345);
}
}
配置
@Autowired
private CustomUserDetails userDetails;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetails);
}
用户端点
@RequestMapping(value = "/user", method = RequestMethod.GET)
@ResponseBody
public Principal getDetails(Principal user) {
return user;
}
此处返回的Principal对象应该包含UserDetails对象,并且应该将其返回给客户端。但是,当您调用getPrincipal();
时,它只返回带有用户名的String最后,我希望User端点(返回Principle对象)返回的JSON包含我添加到UserDetails的自定义字段。
提前致谢。
答案 0 :(得分:5)
通常,您需要注释@AuthenticationPrincipal
,但我建议您构建自己的注释,如下所示:
/**
* Our own {@link AuthenticationPrincipal} annotation as suggested by
* http://docs.spring.io/spring-security/site/docs/3.2.x/reference/htmlsingle/#mvc-authentication-principal
*
*/
@Target({ElementType.PARAMETER, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@AuthenticationPrincipal
public @interface CurrentUser {}
然后你可以这样Principal
:
@RequestMapping(..)
public Principal test(@CurrentUser Principal principal){..}
但是,恕我直言,你应该拥有自己的校长,或者更确切地说是现有的影响。像这样的东西:
public MyPrincipal extends org.springframework.security.core.userdetails.User {..}
在这种情况下,您可以随意返回值。
答案 1 :(得分:-1)
您可以在控制器或任何需要的地方使用此方法获取扩展用户详细信息对象。这种方法可能有利,但有效。
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
MyUserDetails myUser = (MyUserDetails) auth.getPrincipal();
public class MyUserDetails implements
org.springframework.security.core.userdetails.UserDetails {
private User user; //This is the user domain.
private String firstName;
private String lastName;
public Collection<? extends GrantedAuthority> getAuthorities() {
List<GrantedAuthority> authList = new ArrayList<GrantedAuthority>();
authList.add(new SimpleGrantedAuthority(user.getRole().getName()));
return authList;
}
public String getPassword() {
return user.getPassword();
}
public String getUsername() {
return user.getEmail();
}
public boolean isAccountNonExpired() {
return ((user.getAccountState() == AccountState.InActive) || (user.getAccountState() == AccountState.Blocked) ? false : true);
}
public boolean isAccountNonLocked() {
return (user.getAccountState() == AccountState.Locked) ? false : true;
}
public boolean isCredentialsNonExpired() {
return true;
}
public boolean isEnabled() {
return ((user.getAccountState() == AccountState.Active)
|| (user.getAccountState() == AccountState.PasswordReset)
|| (user.getAccountState() == AccountState.UnVerified) ? true
: false);
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
}