Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/url/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
spring security、UserDetailsService、authenticationProvider、密码编码器。。我迷路了_Spring_Spring Security - Fatal编程技术网

spring security、UserDetailsService、authenticationProvider、密码编码器。。我迷路了

spring security、UserDetailsService、authenticationProvider、密码编码器。。我迷路了,spring,spring-security,Spring,Spring Security,首先,我已经反复读了10遍,至少读了6本关于spring和spring安全性的书,我在谷歌上绞尽脑汁想弄清楚这一切 在与spring一起工作了10年之后,我仍然发现有如此多的注释定义、注入、组件、配置注释魔法在进行,以至于我没有信心像我应该理解的那样理解我的应用程序。 在线示例包括xml配置、不完整、以不同方式完成、过于简单、使用较旧的spring、冲突以及只是没有构建来处理基本的实际用例 例如,下面的代码试图处理一个简单的登录,使用密码编码器对db表进行身份验证。 form post包括一个客

首先,我已经反复读了10遍,至少读了6本关于spring和spring安全性的书,我在谷歌上绞尽脑汁想弄清楚这一切

在与spring一起工作了10年之后,我仍然发现有如此多的注释定义、注入、组件、配置注释魔法在进行,以至于我没有信心像我应该理解的那样理解我的应用程序。 在线示例包括xml配置、不完整、以不同方式完成、过于简单、使用较旧的spring、冲突以及只是没有构建来处理基本的实际用例

例如,下面的代码试图处理一个简单的登录,使用密码编码器对db表进行身份验证。 form post包括一个客户端,用户可以向该客户端进行身份验证,一个持久化的IP地址和一些用于深度链接post登录的url路径信息。 今天单页web应用的所有基本功能 我最初使用XMLConfig实现了这一点,但javaConfig让我陷入了困境

我不知道userDetailsService、AuthenticationManagerBuilder和PasswordEncoder在SecurityConfiguration中是如何交互的。我获得了服务的登录数据,但不确定何时何地应用了spring authenticationProvider,或者我是否需要一个

我的用户实现UserDetails并保存必需的字段。 我在CustomUserDetails服务中填充这些内容并授予权限。 如果我在服务中使用登录/密码检查数据库,我如何/何时/为什么需要auth.authenticationProviderauthenticationProvider

我的UserDetails服务现在似乎执行了两次

spring如何获取提交的密码,对其进行编码并与数据库中存储的密码进行比较? 它如何知道使用与创建用户时创建/保留p/w时使用的盐相同的盐

当authenticationProvider还设置userDetailsService时,为什么configureGlobal同时定义auth.userDetailsService和auth.authenticationProvider

为什么我的大脑如此之小以至于我无法理解这一点


哇,好吧,有很多问题。我会对这个人说:

我不知道userDetailsService、AuthenticationManagerBuilder和PasswordEncoder是如何工作的

UserDetailsService设置您可以从Spring访问的。如果希望在用户上下文中存储更多用户信息,则需要实现自己的用户,并使用自定义用户详细信息服务进行设置。e、 g

public class CustomUser extends User implements UserDetails, CredentialsContainer {
private Long id;
private String firstName;
private String lastName;
private String emailAddress;
....
然后,在自定义UserDetails服务中,设置以下属性:

@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
DatabaseEntity databaseUser = this.userRepository.findByUsernameIgnoreCase(username);

customUser customUser = databaseUser.getUserDetails();
customUser.setId(databaseUser.getId());
customUser.setFirstName(databaseUser.getFirstname());
.....
密码编码器是Spring用来将明文密码与数据库中加密的哈希进行比较的机制。您可以使用BCryptPasswordEncoder:

@Bean
public PasswordEncoder passwordEncoder(){
    return new BCryptPasswordEncoder();
}
除了将其传递给身份验证提供者之外,您还需要做更多的工作

最后,configureGlobal是连接东西的地方。您可以定义Spring要使用的用户详细信息服务和身份验证提供程序

在我的情况下,我使用自定义身份验证提供程序来限制失败的登录尝试:

@Component("authenticationProvider")
public class LimitLoginAuthenticationProvider extends DaoAuthenticationProvider {
然后我把一切都连接起来:

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

@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
    LimitLoginAuthenticationProvider provider = (LimitLoginAuthenticationProvider)authenticationProvider;
    provider.setPasswordEncoder(passwordEncoder);
    auth.userDetailsService(customUserDetailsService()).passwordEncoder(passwordEncoder);
    auth.authenticationProvider(authenticationProvider);
}

哇,好吧,有很多问题。我会对这个人说:

我不知道userDetailsService、AuthenticationManagerBuilder和PasswordEncoder是如何工作的

UserDetailsService设置您可以从Spring访问的。如果希望在用户上下文中存储更多用户信息,则需要实现自己的用户,并使用自定义用户详细信息服务进行设置。e、 g

public class CustomUser extends User implements UserDetails, CredentialsContainer {
private Long id;
private String firstName;
private String lastName;
private String emailAddress;
....
然后,在自定义UserDetails服务中,设置以下属性:

@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
DatabaseEntity databaseUser = this.userRepository.findByUsernameIgnoreCase(username);

customUser customUser = databaseUser.getUserDetails();
customUser.setId(databaseUser.getId());
customUser.setFirstName(databaseUser.getFirstname());
.....
密码编码器是Spring用来将明文密码与数据库中加密的哈希进行比较的机制。您可以使用BCryptPasswordEncoder:

@Bean
public PasswordEncoder passwordEncoder(){
    return new BCryptPasswordEncoder();
}
除了将其传递给身份验证提供者之外,您还需要做更多的工作

最后,configureGlobal是连接东西的地方。您可以定义Spring要使用的用户详细信息服务和身份验证提供程序

在我的情况下,我使用自定义身份验证提供程序来限制失败的登录尝试:

@Component("authenticationProvider")
public class LimitLoginAuthenticationProvider extends DaoAuthenticationProvider {
然后我把一切都连接起来:

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

@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
    LimitLoginAuthenticationProvider provider = (LimitLoginAuthenticationProvider)authenticationProvider;
    provider.setPasswordEncoder(passwordEncoder);
    auth.userDetailsService(customUserDetailsService()).passwordEncoder(passwordEncoder);
    auth.authenticationProvider(authenticationProvider);
}
我的用户实现UserDetails并保存必需的字段。我 在my CustomUserDetails服务中填充这些和授予的权限。 如何/何时/为什么我需要 auth.authenticationProviderauthenticationProvider,如果我检查db 在我的服务中使用登录/密码

我想你想要的是:

@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
    auth.userDetailsService(customUserDetailsService).passwordEncoder(passwordEncoder());
}
userDetailsService方法是创建DaoAuthenticationProviderbean的快捷方式!你不应该两者都需要,它只是两种不同的方式来配置相同的东西。authenticationProvider方法用于更多自定义设置

spring如何获取提交的密码、对其进行编码并与之进行比较 存储在数据库中的数据?它怎么知道要用和那一样的盐 是否在创建用户时创建/保留p/w时使用

如果您使用的是BCrypt,salt将存储在编码的密码值中 . 盐是第三个美元符号后的前22个字符。该方法负责检查密码

为什么configureGlobal同时定义auth.userDetailsService和 当authenticationProvider也设置为 用户详细信息服务

见上文。这可能就是用户详细信息被加载两次的原因

更新:将密码和其他详细信息输入到UserDetails服务中是很奇怪的。这应仅基于用户名加载用户,例如:

User user = userDAO.getUserByUserLogonPassword(userLogon);
返回的用户对象应包含编码的存储密码,而不是输入的密码。Spring Security为您执行密码检查。不应修改UserDetails服务中的用户对象

我的用户实现UserDetails并保存必需的字段。我 在my CustomUserDetails服务中填充这些和授予的权限。 如何/何时/为什么我需要 auth.authenticationProviderauthenticationProvider,如果我检查db 在我的服务中使用登录/密码

我想你想要的是:

@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
    auth.userDetailsService(customUserDetailsService).passwordEncoder(passwordEncoder());
}
userDetailsService方法是创建DaoAuthenticationProviderbean的快捷方式!你不应该两者都需要,它只是两种不同的方式来配置相同的东西。authenticationProvider方法用于更多自定义设置

spring如何获取提交的密码、对其进行编码并与之进行比较 存储在数据库中的数据?它怎么知道要用和那一样的盐 是否在创建用户时创建/保留p/w时使用

如果您使用的是BCrypt,salt将存储在编码的密码值中。盐是第三个美元符号后的前22个字符。该方法负责检查密码

为什么configureGlobal同时定义auth.userDetailsService和 当authenticationProvider也设置为 用户详细信息服务

见上文。这可能就是用户详细信息被加载两次的原因

更新:将密码和其他详细信息输入到UserDetails服务中是很奇怪的。这应仅基于用户名加载用户,例如:

User user = userDAO.getUserByUserLogonPassword(userLogon);

返回的用户对象应包含编码的存储密码,而不是输入的密码。Spring Security为您执行密码检查。您不应修改UserDetails服务中的用户对象。

thx以获得响应。是的,我看到我的帖子会让人认为我对userService、javaConfig等响应的基本机制一无所知。是的,我看到我的帖子会让人认为我对userService、javaConfig等的基本机制一无所知。但正如我所包含的代码所证明的那样,我拥有你提到的所有设置。我实际上调用了一个dao,该dao使用用户名和密码获取用户实现UserDetails。当用户只通过用户名加载时,我看不出安全性是如何工作的。是否使用密码再次查找UserDetails?它是如何/何时加密的,因为它与数据库中的加密值相比?spring自动处理这个问题吗?spring如何知道使用相同的salt?断点显示服务中检索并填充的用户。我甚至尝试手动将encodedPassword设置为db存储值。我获得了一个用户,但仍然无法通过spring身份验证。我不得不认为编码器没有被应用。我无法想象我在服务中手动添加:新的BCryptPasswordEncoder来加密提交的p/w,因为salt可能会有所不同。在DaoAuthenticationProvider中,实际的密码检查会发生。请参阅其他身份验证检查。在我的情况下,使用自定义身份验证提供程序,我调用super:@Override public authentication authentication authentication throws AuthenticationException{try{Authentication auth=super.authenticateauthentication;在我的例子中,在实现新的UserDetailsService之后,我没有更新auth.userDetailsServiceXXX下的类名,因此我一直得到身份验证失败的错误:密码与响应Brian的存储值不匹配。是的,我看到我的帖子将导致一个错误o假设我对userService、javaConfig等的基本机制一无所知。对于Brian的响应,thx。是的,我看到我的帖子会让人认为我对userService、javaConfig等的基本机制一无所知。但是,正如我所包含的代码所证明的,我有你提到的所有设置。我实际上调用了一个dao来获取用户implements UserDetails使用用户名和密码。我看不出当用户仅通过用户名加载时安全性如何工作。是否有另一个使用密码的UserDetails查询?由于它与来自db的加密值相比较,它是如何/何时加密的?spring是否自动处理此问题?spring如何知道使用相同的salt?断点显示ret在服务中保存并填充用户。我甚至尝试手动将encodedPassword设置为db存储值。我获得了一个用户,但仍然无法通过spring身份验证。我不得不认为编码器未被应用。我无法
我手动添加的想象:新的BCryptPasswordEncoder在服务中加密提交的p/w,因为salt可能不同。在DaoAuthenticationProvider中,实际的密码检查会发生。请参阅其他身份验证检查。在我的情况下,使用自定义身份验证提供程序,我调用super:@Override public authentication authentication authentication throws AuthenticationException{try{Authentication auth=super.authenticateauthentication;在我的情况下,在实现新的UserDetailsService之后,我没有更新auth.userDetailsServiceXXX下的类名,因此我一直得到身份验证失败的错误:密码与存储值不匹配哈!thx,salt答案非常有用。我们仅限UserDetailsService,是的,这就是我最初的定义方式。我也有一个与您的定义完全相同的passwordEncoder。在在线示例中,人们倾向于将这些东西以9种方式放在一起,希望它们能起作用。我的问题是,我的CustomUserDetailsService.loadUserByUsername使用冒号分隔的字符串,其中包含的不仅仅是username、 它包含logon:password:clientId:entryUrl:etc。但是,在调用DaoAuthProvider.retrieveUserString username..之后,将使用到loadUserByUsername的原始多部分登录,并且失败。事实上,DaoAuthenticationProvider具有正确的loadedUser,但AbstractDetailsAuthenticationProvider Authentication使用原始冒号-分隔的用户名,这是身份验证失败的时间。用户名,p/w查找是我自定义的。我更新为只检查用户名。问题是,CustomUserDetails服务工作正常,p/w正确自动加密..但随后调用了DaoAuthenticationProvider.retrieveUser,该方法使用最初提交的multipartLogon,其中包含:[userName]:[clientId]:[requestedUrl];[IPAddress]:等。这是因为我需要的不仅仅是用户名,登录和userDetails的p/w。loadUserByUsername只接受一个字符串arg,它会自动传递给DaoAuteHandicationProvider。@oldMan再次阅读。不要在userDetails服务中弄乱密码之类的东西!哈!thx,salt的答案非常有用。我们只接受userDetails服务,是的我使用它的方式。我也使用了与您的完全相同的passwordEncoder定义。在在线示例中,人们倾向于将这些东西以9种方式放在一起,希望能起作用。我的问题是我的CustomUserDetailsService.loadUserByUsername使用冒号分隔的字符串,其中包含的不仅仅是用户名。它包含logon:password:clientId:entryUrl:etc。但是,在调用DaoAuthProvider.retrieveUserString username..之后,将使用对loadUserByUsername的原始多部分登录,并且失败。事实上,DaoAuthenticationProvider具有正确的loadedUser,但AbstractDetailsAuthenticationProvider Authentication使用原始冒号分隔的用户用户名,p/w查找是我自定义的。我更新为只检查用户名。问题是,CustomUserDetails服务工作正常,p/w正确自动加密。但随后调用了DaoAuthenticationProvider.retrieveUser,该方法使用最初提交的multipartLogon,其中包含:[用户名]:[clientId]:[requestedUrl];[IPAddress]:等等。这是因为我需要的不仅仅是用户名,登录和userDetails的p/w。loadUserByUsername只接受一个字符串arg,它会自动传递给DaoAuteHandicationProvider。@oldMan请重新阅读。不要在userDetails服务中弄乱密码之类的东西!