尽管使用Spring Security中的自定义用户详细信息类,但主体仍保留字符串

时间:2018-11-06 15:42:03

标签: java spring-boot spring-security

我有一个自定义UserDetailsService,如下所示:

@Service
public class AuthenticatedUserService implements UserDetailsService {

    private final UserRepository userRepository;

    @Autowired
    public AuthenticatedUserService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    @Override
    public UserDetails loadUserByUsername(String username) {
        UserCredentials userCredentials = userRepository.findByUsername(username);
        if (userCredentials == null) {
            throw new UsernameNotFoundException("The user " + username + " does not exist");
        }
        return new AuthenticatedPrincipal(userCredentials);
    }
}

我的AuthenticatedPrincipal如下:

public class AuthenticatedPrincipal implements UserDetails {
    private UserCredentials userCredentials;

    public AuthenticatedPrincipal() {

    }

    public AuthenticatedPrincipal(UserCredentials userCredentials) {
        this.userCredentials = userCredentials;
    }

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        List<GrantedAuthority> authorities = new ArrayList<>();
        ...
        return authorities;
    }

    @Override
    public String getPassword() {
        return userCredentials.getPassword();
    }

    @Override
    public String getUsername() {
        return userCredentials.getUsername();
    }

    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }

    @Override
    public boolean isEnabled() {
        return true;
    }
}

我以这种方式使用服务:

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Qualifier("authenticatedUserService")
    @Autowired
    private UserDetailsService userDetailsService;

    @Autowired
    protected void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        // auth.ldapAuthentication()

        auth.userDetailsService(userDetailsService)
            .passwordEncoder(passwordEncoder);
    }

    ...
}

一切正常。我可以登录。但是我从来没有得到我的自定义主体。在每个地方,只需获取一个包含用户名的纯字符串即可。例如,我要实现自定义SecurityExpressionRoot

public class CustomMethodSecurityExpressionRoot
    extends SecurityExpressionRoot implements MethodSecurityExpressionOperations {

    public CustomMethodSecurityExpressionRoot(Authentication authentication) {
        super(authentication);
    }

    public boolean isMember(Long OrganizationId) {
        // Throws an exception, because principal is just a string
        AuthenticatedPrincipal user = (AuthenticatedPrincipal) this.getPrincipal();
        return false;
    }

当我尝试将其插入我的一个控制器中时,也会发生同样的情况。

public ResponseEntity listMessages(@AuthenticationPrincipal Principal principal) {

我不知道该怎么办然后再尝试。例如,我认为自己所做的工作与this tutorial没有什么区别。

2 个答案:

答案 0 :(得分:1)

尝试在控制器中将主体类型从“主体”更改为“ AuthenticatedPrincipal”。

答案 1 :(得分:1)

好的,我已经设法找到并解决了我的问题。我正在使用JWT,并且正在使用自定义过滤器来设置身份验证。我没有返回适当的Authentication对象,而是一直使用默认的UsernamePasswordAuthenticationToken。为了解决这个问题,我继续创建了自己的令牌类:

public class TokenBasedAuthentication extends AbstractAuthenticationToken {
    private final UserDetails principal;

    public TokenBasedAuthentication(AuthenticatedPrincipal principal) {
        super(principal.getAuthorities());
        this.principal = principal;
    }

    @Override
    public boolean isAuthenticated() {
        return true;
    }

    @Override
    public UserDetails getPrincipal() {
        return principal;
    }
}

然后,在我的过滤器中,我继续创建了一个正确的身份验证对象:

AuthenticatedPrincipal userDetails = (AuthenticatedPrincipal) userDetailsService.loadUserByUsername(username);
TokenBasedAuthentication authentication = new TokenBasedAuthentication(userDetails);
SecurityContextHolder.getContext().setAuthentication(authentication);

现在我也要找到合适的校长。其实本该早点解决的,但我想很好。