0

我有:

@Service
public class MyAppUserDetailsService implements UserDetailsService {

@Autowired
private IUserInfoDAO userInfoDAO;

@Override
public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException {

    User activeUserInfo                   = userInfoDAO.getActiveUser(userName);
    GrantedAuthority authority            = new SimpleGrantedAuthority(activeUserInfo.getRole());


    String userNameVal                    = activeUserInfo.getUserName();
    String userSurnameVal                 = activeUserInfo.getPassword();

    UserDetails userDetails = new org.springframework.security.core.userdetails.User(userNameVal, userSurnameVal, Arrays.asList(authority));
    return userDetails;
}
}

和:

在我配置的安全链中:

   .and().formLogin()  //login configuration
                .loginPage("/app/login")
                .loginProcessingUrl("/app-login")
                .usernameParameter("app_username")
                .passwordParameter("app_password")
                .defaultSuccessUrl("/app/secure/projects-details")

填写表单的用户密码如何与 loadUserByUsername 方法中设置的 UserDetails 进行比较?

4

1 回答 1

2

一旦你告诉 Spring 安全配置你将使用一个特定的UserDetailsService或只有一个@Servicebean 是该接口的实现,然后 Spring 开始使用它从持久存储中按用户名获取用户。让我们简化流程:

  1. 用户提交一个表单,其中包含名称app_usernameapp_password存在的字段(如网络安全配置中配置的那样)到loginPage(String)路由

  2. 表单提交被 Spring Security 的 Filter Chain 拦截,Spring 知道用户名在字段中app_username密码在字段中app_password

  3. 配置的UserDetailsServicebean 现在被激活,它的loadUserByUsername(String)方法被调用并且app_username字段的值被传递(例如john_smith

  4. 由于该loadUserByUsername(String)方法是按合同设计的,旨在返回它的实现,UserDetails它总是返回一个包含getUsername()getPassword()方法的对象

  5. 然后 Spring 使用getPassword()合约中的方法并将密码与app_password字段(例如super_s3cr3t_password)进行比较

  6. 如果passwordEncoder()在 Spring Security Config 中配置或者PasswordEncoder接口的实现注册为 bean,那么 spring 使用isPasswordValid(String, String, Object)方法来验证app_password字段的内容和UserDetails.getPassword()方法的结果

  7. 如果UserDetailsService没有抛出UsernameNotFoundException并且 fetched匹配过滤UserDetails器链继续执行其他过滤器,否则它会阻止用户登录到应用程序getPassword()app_password

如果代码示例可以更好地简化它,那么想象以下伪 java 代码:

String usernameField = this.getConfiguredUsernameParameter(); // app_username
String passwordField = this.getConfiguredPasswordParameter(); // app_password
UserDetails userDetails = this.registeredUserDetailsImplementation.loadUserByUsername(request.getParameter(usernameField));
String passwordHash = userDetails.getPassword();
String rawPassword = request.getParameter(passwordField);
String salt = this.getConfiguredSalt(); // can be null
if (this.configuredPasswordEncoder.isPasswordValid(passwordHash, rawPassword, salt) {
   return true;
}

return false;

请记住,这不是幕后的 Spring Security Code,而只是解释的简化代码说明。

于 2018-04-23T13:24:32.763 回答