Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/spring-mvc/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java loadUserByUsername使用DaoAuthenticationProvider执行两次_Java_Spring Mvc_Spring Security - Fatal编程技术网

Java loadUserByUsername使用DaoAuthenticationProvider执行两次

Java loadUserByUsername使用DaoAuthenticationProvider执行两次,java,spring-mvc,spring-security,Java,Spring Mvc,Spring Security,我正在使用DaoAuthenticationProvider进行身份验证,但当我提交表单loadUserByUsername时,super会调用两次。身份验证(authentication)最初会引发BadCredentialsException,然后在下次成功登录时抛出 若我不使用passwordencoder,这个过程运行良好,但当我使用它时,loadUserByUsername方法被调用两次 下面是我的代码: SecurityConfig @Configuration @EnableWeb

我正在使用DaoAuthenticationProvider进行身份验证,但当我提交表单loadUserByUsername时,super会调用两次。身份验证(authentication)最初会引发BadCredentialsException,然后在下次成功登录时抛出

若我不使用passwordencoder,这个过程运行良好,但当我使用它时,loadUserByUsername方法被调用两次

下面是我的代码:

SecurityConfig

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

@Autowired
@Qualifier("authenticationProvider")
AuthenticationProvider authenticationProvider;

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

@Bean
public PasswordEncoder passwordEncoder() {
    PasswordEncoder encoder = new BCryptPasswordEncoder();
    return encoder;
}

@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth)
        throws Exception {
    auth.authenticationProvider(authenticationProvider)
    .userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}

@Override
protected void configure(HttpSecurity http) throws Exception {

    http.authorizeRequests().antMatchers("/admin/**")
            .access("hasRole('ROLE_ADMIN')").and().formLogin()
            .loginPage("/login").failureUrl("/login?error")
            .usernameParameter("username").passwordParameter("password")
            .and().logout().logoutSuccessUrl("/login?logout").and().csrf()
            .and().exceptionHandling().accessDeniedPage("/403");
}

}
身份验证类

@Component("authenticationProvider")
public class LimitLoginAuthenticationProvider extends DaoAuthenticationProvider {

@Autowired
@Qualifier("userDetailsService")
@Override
public void setUserDetailsService(UserDetailsService userDetailsService) {
    super.setUserDetailsService(userDetailsService);
}

@Override
public Authentication authenticate(Authentication authentication)
        throws AuthenticationException {

    try {
        System.out.println("inside authenticate");
        Authentication auth = super.authenticate(authentication);
        return auth;
    } catch (BadCredentialsException be) {
        System.out.println("First call comes here ");
        throw be;
    } catch (LockedException e) {
        throw e;
    }
}
}
MyUserdetailsService类实现UserDetailsService

@Service("userDetailsService")
public class MyUserDetailsService implements UserDetailsService {

@Autowired
private UserDao userDao;

/* below method is called twice if I am using passwordencoder,
initially authentication fails and then again immediately 
on second call authentication succeed */

@Transactional(readOnly=true)
@Override
public UserDetails loadUserByUsername(final String username) throws UsernameNotFoundException {

    com.mkyong.users.model.User user = userDao.findByUserName(username);
    List<GrantedAuthority> authorities = buildUserAuthority(user.getUserRole());

    return buildUserForAuthentication(user, authorities);

}

private User buildUserForAuthentication(com.mkyong.users.model.User user, List<GrantedAuthority> authorities) {
     MyUserDetails myUserDetails = new MyUserDetails (user.getUsername(), user.getPassword(), user.isEnabled(), user.isAccountNonExpired(), user.isAccountNonLocked(), user.isCredentialsNonExpired(), user.getEmailId(),authorities);
     return myUserDetails;
}

private List<GrantedAuthority> buildUserAuthority(Set<UserRole> userRoles) {

    Set<GrantedAuthority> setAuths = new HashSet<GrantedAuthority>();

    // Build user's authorities
    for (UserRole userRole : userRoles) {
        setAuths.add(new SimpleGrantedAuthority(userRole.getRole()));
    }

    List<GrantedAuthority> Result = new ArrayList<GrantedAuthority>(setAuths);

    return Result;
}

}
@Service(“userdetailssservice”)
公共类MyUserDetailsService实现UserDetailsService{
@自动连线
私有UserDao UserDao;
/*如果使用passwordencoder,则调用下面的方法两次,
最初身份验证失败,然后立即再次失败
第二次呼叫身份验证成功*/
@事务(只读=真)
@凌驾
public UserDetails loadUserByUsername(最终字符串用户名)引发UsernameNotFoundException{
com.mkyong.users.model.User User=userDao.findByUserName(用户名);
列表权限=buildUserAuthority(user.getUserRole());
返回buildUserForAuthentication(用户、权限);
}
私人用户buildUserForAuthentication(com.mkyong.users.model.User用户,列出权限){
MyUserDetails MyUserDetails=新的MyUserDetails(user.getUsername()、user.getPassword()、user.isEnabled()、user.isAccountNonExpired()、user.isAccountNonLocked()、user.isCredentialsNonExpired()、user.getEmailId()、Authority);
返回myUserDetails;
}
私有列表buildUserAuthority(设置用户角色){
Set setAuths=new HashSet();
//建立用户权限
for(用户角色用户角色:用户角色){
添加(新的SimpleGrantedAuthority(userRole.getRole());
}
列表结果=新的ArrayList(setAuths);
返回结果;
}
}

请给我一些。我相信在SecurityConfig类中需要进行一些更改,但具体到哪里我还不知道。

在java_dude和SergeBallesta的帮助下,我终于得到了查询的解决方案

经过大量调试后,我发现当isPasswordValid方法在DaoAuthenticationProvider类中被调用时,而不是调用方法1时,它正在从org.springframework.security.authentication.encoding.PlaintextPasswordEncoder调用方法2,其中一个被折旧,第二次调用时它正在调用正确的isPasswordValid 方法1

方法1

 public boolean isPasswordValid(String encPass, String rawPass, Object salt) {
                checkSalt(salt);
                return delegate.matches(rawPass, encPass);
            }
方法2

 public boolean isPasswordValid(String encPass, String rawPass, Object salt) {
    String pass1 = encPass + "";

    // Strict delimiters is false because pass2 never persisted anywhere
    // and we want to avoid unnecessary exceptions as a result (the
    // authentication will fail as the encodePassword never allows them)
    String pass2 = mergePasswordAndSalt(rawPass, salt, false);

    if (ignorePasswordCase) {
        // Note: per String javadoc to get correct results for Locale insensitive, use English
        pass1 = pass1.toLowerCase(Locale.ENGLISH);
        pass2 = pass2.toLowerCase(Locale.ENGLISH);
    }
    return PasswordEncoderUtils.equals(pass1,pass2);
}
要正确地进行身份验证,只需在SecurityConfig类中添加以下代码,并将其添加到我当前正在讨论的代码中

@Bean
public DaoAuthenticationProvider authProvider() {
 // LimitLoginAuthenticationProvider is my own class which extends DaoAuthenticationProvider 
    final DaoAuthenticationProvider authProvider = new LimitLoginAuthenticationProvider(); 
    authProvider.setUserDetailsService(userDetailsService);
    authProvider.setPasswordEncoder(passwordEncoder());
    return authProvider;
}
**并更改此方法代码**

@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
    auth.authenticationProvider(authProvider())
 .userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}

我可以看一看,但你必须把它放在
github
上,我才能看一看。有很多东西可以看。您的
XML配置
。你能拿出一个样本项目吗?@java_dude。好的,我将把我的项目放在github中。@java\u dude还有其他地方可以直接复制我的项目并粘贴吗。Github查找小困难查看此文档以了解
Github
https://guides.github.com/activities/hello-world/
。如果您仍然觉得有困难,请将其放在您的
谷歌硬盘上。与
public
共享并在此处提供链接,我将访问该链接并将其放在
github
@java\u dude上。我已提交该链接的文件和url