身份验证后,SecurityContextHolder.getContext()。getAuthentication()。getCredentials()返回null

时间:2018-11-27 09:18:12

标签: java spring-mvc spring-security

我创建了一个简单的spring web mvc应用程序,但我遇到了一个问题。身份验证后,我尝试获取身份验证对象,由于某种原因,它的凭据为null。

enter image description here

在这个项目中,我有一个自定义的AuthenticationProvider,如下所示:

@Component
public class CustomAuthenticationProvider implements AuthenticationProvider {

    @Autowired
    private UserService userService;

    @Autowired
    private RoleService roleService;

    @PostConstruct
    public void init() {
        roleService.AddStandardRolesIfNeeded();
        userService.AddUserWithAdminRoleIfNotExists("a"); 
    }


    public Authentication authenticate(Authentication authentication) throws AuthenticationException {


        Object credentials = authentication.getCredentials();
        if(!(credentials instanceof String)) {
            return null;
        }

        String username = authentication.getName();
        String password = credentials.toString(); //password isn't null here


        User user = userService.findByUsernameAndPassword(username, password);


        if(user == null) {
            throw new BadCredentialsException("Authentication failed for " + username);
        }


        List<GrantedAuthority> authorities = new ArrayList<>();
        for(Role role : user.getRoles()) {
            authorities.add(new SimpleGrantedAuthority(role.getName()));
        }

        Authentication auth = new 
                UsernamePasswordAuthenticationToken(username, password, authorities);


        return auth;
    }

    public boolean supports(Class<?> authentication) {
        return authentication.equals(UsernamePasswordAuthenticationToken.class);
    }

}

我对是否有意在春季安全中完成它或我遗漏了一些东西感兴趣。

3 个答案:

答案 0 :(得分:0)

我通过将用户对象传递给UsernamePasswordAuthenticationToken构造函数而不是用户名代替主体来解决了这个问题。

我更改了此内容

Authentication auth = new 
                UsernamePasswordAuthenticationToken(username, password, authorities);

对此:

Authentication auth = new 
                    UsernamePasswordAuthenticationToken(user, password, authorities);

在控制器中,我得到了用户,

User user = (User)SecurityContextHolder.getContext().getAuthentication().getPrincipal();

答案 1 :(得分:0)

由于认证成功后凭据将被删除,因此必须将eraseCredentials(false)添加到AuthenticationManagerBuilder配置中。就像下面的代码:

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth.authenticationProvider(customAuthProvider).eraseCredentials(false);
}

这很晚了,但是我认为这是根据问题的正确答案。

答案 2 :(得分:-1)

应该使身份验证更像这样:

@Override
public Authentication authenticate(final Authentication authentication) {
    //better to use optionals with repositories, they greatly reduce NullPointer exception quantity
    final SomeUser user = UserRepository.findByUsernameIgnoreCase(authentication.getName())
                .orElseThrow(() -> new UsernameNotFoundException("some message"));
    try {
            final Authentication auth = super.authenticate(authentication);
            //can add logic here, such as login time recording
            return auth;
    } catch (...) {
           //handle various exceptions here, for example failed login attempts and user locking
    }