Spring Security使用用户名或电子邮件

dluptydi  于 2024-01-05  发布在  Spring
关注(0)|答案(8)|浏览(149)

我在我的Spring MVC应用程序中使用Spring Security。
JdbcUserDetailsManager使用以下验证查询初始化:

  1. select username, password, enabled from user where username = ?

字符串
当局正在加载这里:

  1. select u.username, a.authority from user u join authority a on u.userId = a.userId where username = ?


我想让它,使用户可以登录用户名和电子邮件。有没有办法修改这两个查询来实现这一点?或者有一个更好的解决方案?

e37o9pze

e37o9pze1#

不幸的是,没有简单的方法可以通过更改查询来做到这一点。问题是spring security期望users-by-username-query和authorities-by-username-query具有单个参数(用户名),因此如果您的查询包含两个参数,如

  1. username = ? or email = ?

字符串
查询将失败。
你可以做的是实现你自己的UserDetailsService,它将执行查询(或多个查询),通过用户名或电子邮件搜索用户,然后在你的spring安全配置中使用这个实现作为身份验证提供者,比如

  1. <authentication-manager>
  2. <authentication-provider user-service-ref='myUserDetailsService'/>
  3. </authentication-manager>
  4. <beans:bean id="myUserDetailsService" class="xxx.yyy.UserDetailsServiceImpl">
  5. </beans:bean>

lymnna71

lymnna712#

我也遇到了同样的问题,在尝试了很多不同的查询,程序.

  1. public void configAuthentication(AuthenticationManagerBuilder auth)
  2. throws Exception {
  3. // Codificación del hash
  4. PasswordEncoder pe = new BCryptPasswordEncoder();
  5. String userByMailQuery = "SELECT mail, password, enabled FROM user_ WHERE mail = ?;";
  6. String userByUsernameQuery = "SELECT mail, password, enabled FROM user_ WHERE username=?";
  7. String roleByMailQuery = "SELECT mail, authority FROM role WHERE mail =?;";
  8. auth.jdbcAuthentication().dataSource(dataSource).passwordEncoder(pe)
  9. .usersByUsernameQuery(userByMailQuery)
  10. .authoritiesByUsernameQuery(roleByMailQuery);
  11. auth.jdbcAuthentication().dataSource(dataSource).passwordEncoder(pe)
  12. .usersByUsernameQuery(userByUsernameQuery)
  13. .authoritiesByUsernameQuery(roleByMailQuery);
  14. }

字符串
它只是用两个查询重复配置。

展开查看全部
xkftehaa

xkftehaa3#

如果我理解正确的话,那么问题是您希望在两个不同的DB列中查找用户输入的用户名。
当然,你可以通过自定义UserDetailsService来实现。

  1. public class CustomJdbcDaoImpl extends JdbcDaoImpl {
  2. @Override
  3. protected List<GrantedAuthority> loadUserAuthorities(String username) {
  4. return getJdbcTemplate().query(getAuthoritiesByUsernameQuery(), new String[] {username, username}, new RowMapper<GrantedAuthority>() {
  5. public GrantedAuthority mapRow(ResultSet rs, int rowNum) throws SQLException {
  6. .......
  7. }
  8. });
  9. }
  10. @Override
  11. protected List<UserDetails> loadUsersByUsername(String username) {
  12. return getJdbcTemplate().query(getUsersByUsernameQuery(), new String[] {username, username}, new RowMapper<UserDetails>() {
  13. public UserDetails mapRow(ResultSet rs, int rowNum) throws SQLException {
  14. .......
  15. }
  16. });
  17. }

字符串
这个类的bean配置如下所示。

  1. <beans:bean id="customUserDetailsService" class="com.xxx.CustomJdbcDaoImpl">
  2. <beans:property name="dataSource" ref="dataSource"/>
  3. <beans:property name="usersByUsernameQuery">
  4. <beans:value> YOUR_QUERY_HERE</beans:value>
  5. </beans:property>
  6. <beans:property name="authoritiesByUsernameQuery">
  7. <beans:value> YOUR_QUERY_HERE</beans:value>
  8. </beans:property>
  9. </beans:bean>


您的查询将类似于以下内容

  1. select username, password, enabled from user where (username = ? or email = ?)
  2. select u.username, a.authority from user u join authority a on u.userId = a.userId where (username = ? or email = ?)

展开查看全部
cyej8jka

cyej8jka4#

您可以像下面的代码一样使用UserDetailesService.和config。

  1. @EnableWebSecurity
  2. public class SecurityConfig extends WebSecurityConfigurerAdapter {
  3. @Autowired
  4. private MyUserDetailsService userDetailsService;
  5. @Override
  6. protected void configure(AuthenticationManagerBuilder auth) throws Exception {
  7. auth.userDetailsService(userDetailsService);
  8. }
  9. }

字符串
关键是,你不需要返回用户相同的用户名,你可以得到用户的电子邮件和返回用户的用户名。代码将像下面的代码。

  1. @Service
  2. public class MyUserDetailsService implements UserDetailsService {
  3. @Override
  4. public UserDetails loadUserByUsername(String usernameOrEmail) throws UsernameNotFoundException {
  5. var user = /** here search user via jpa or jdbc by username or email **/;
  6. if(user == null )
  7. throw new UsernameNotFoundExeption();
  8. else return new UserDetail(user); // You can implement your user from UserDerail interface or create one;
  9. }
  10. }


tip* UserDetail是一个接口,您可以创建一个或使用Spring Default。

展开查看全部
jw5wzhpr

jw5wzhpr5#

您可以分别在users-by-username-queryauthorities-by-username-query属性中的<jdbc-user-service>标记中定义自定义查询。

  1. <jdbc-user-service data-source-ref="" users-by-username-query="" authorities-by-username-query=""/>

字符串

更新

您可以创建实现org.springframework.security.core.userdetails.UserDetailsService的类,并配置应用程序将其用作身份验证源。在自定义UserDetails服务中,您可以执行从数据库获取用户所需的查询。

avkwfej4

avkwfej46#

你可以像这样配置UserDetailesService类。

  1. public class UserDetailsServiceImpl implements UserDetailsService{
  2. @Autowired
  3. private UserRepository userRepository;
  4. @Override
  5. public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
  6. User user = this.userRepository.getUserByEmailOrUserName(username); //for fetch user
  7. if(user==null) {
  8. throw new UsernameNotFoundException("User doesn't exists");
  9. }
  10. UserDetailsImpl customUserDetails = new UserDetailsImpl(user);
  11. return customUserDetails;
  12. }
  13. }

字符串
您的查询将类似于以下内容
select * from user where email =?or username =?
用于获取用户数据的UserRepository类

  1. @Repository
  2. public interface UserRepository extends JpaRepository<User, Integer>{
  3. @Query("from user where email = :u or username = :u")
  4. public User getUserByEmailOrUserName(@Param("u") String username);
  5. }


您也可以在登录时添加电话号码。

展开查看全部
yb3bgrhw

yb3bgrhw7#

这里是我发现的一个解决方法。基本上,我将用户名和电子邮件地址连接在一起,中间有一个字符(例如'email protected(https://stackoverflow.com/cdn-cgi/l/email-protection)'),并检查参数是否匹配字符串的左侧或右侧:

  1. select username, password, enabled
  2. from users
  3. where ? in (substring_index(concat(username, '~',email),'~', 1),
  4. substring_index(concat(username, '~',email),'~', -1))

字符串
如果您担心用户名或电子邮件中可能会存在“”字符(例如~),请改用非标准的“”字符(例如X '9 C“)。

6fe3ivhb

6fe3ivhb8#

你可以按如下方式更改你的配置:

  1. @Bean
  2. public UserDetailsService userDetailsService() {
  3. return input -> repository.findByUsername(input)
  4. .orElseGet(() -> repository.findByEmail(input)
  5. .orElseThrow(() -> new UsernameNotFoundException("account not found")));
  6. }

字符串

相关问题