2013-01-02 11 views
7

Używam Spring Security w mojej aplikacji Spring MVC.Bezpieczeństwo wiosenne przy użyciu zarówno nazwy użytkownika, jak i adresu e-mail

JdbcUserDetailsManager jest inicjowany z następującym zapytaniem do uwierzytelniania:

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

a władze są ładowane są tutaj:

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

Chciałbym, aby tak było, że użytkownicy mogą zalogować się zarówno nazwę użytkownika i e-mail. Czy istnieje sposób, aby zmodyfikować te dwa zapytania, aby to osiągnąć? Czy istnieje jeszcze lepsze rozwiązanie?

Odpowiedz

4

Niestety, nie ma łatwego sposobu robienia tego po prostu przez zmianę zapytań. Problem polega na tym, że bezpieczeństwo wiosna spodziewa się, że użytkownicy po nazwa użytkownika-zapytania i władze po nazwa użytkownika-zapytania mieć jeden parametr (nazwę użytkownika), więc jeśli zapytanie zawiera dwa parametry jak

username = ? or email = ? 

zapytanie zawiedzie .

Co można zrobić, to zaimplementować własną UserDetailsService że wykona zapytanie (lub zapytania), aby wyszukać użytkownika przez użytkownika lub adres e-mail, a następnie użyć tej implementacji jak uwierzytelnianie-operatora w konfiguracji zabezpieczeń wiosny jak

<authentication-manager> 
    <authentication-provider user-service-ref='myUserDetailsService'/> 
    </authentication-manager> 

    <beans:bean id="myUserDetailsService" class="xxx.yyy.UserDetailsServiceImpl"> 
    </beans:bean> 
+0

Spojrzałem na klasy, ale mam problem z ustaleniem, które metody powinienem nadpisać. Jakieś wskazówki? – tumanov

+1

Myślę, że widzę to teraz: loadUserByUsername (String username) – tumanov

1

Można zdefiniować niestandardowe zapytania w tagach <jdbc-user-service> w atrybutach users-by-username-query i authorities-by-username-query.

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

Aktualizacja

Można utworzyć klasę, która implementuje org.springframework.security.core.userdetails.UserDetailsService i skonfigurować aplikację, aby używać go jako źródła uwierzytelniania. Wewnątrz niestandardowej usługi UserDetails można wykonywać kwerendy, których potrzebujesz do uzyskania użytkownika z bazy danych.

+0

Dokładnie to już robiłem i uwzględniłem je w moim pytaniu. Problem polega na tym, że muszę je dostosować tak, aby zawierały zarówno nazwę użytkownika, jak i adres e-mail. – tumanov

+0

Nie wspominałeś, że umiesz je konfigurować. I pytasz "Czy istnieje sposób, aby zmodyfikować te dwa zapytania, aby to osiągnąć?". –

+0

W każdym razie zaktualizowałem swoją odpowiedź. –

2

Jeśli zrozumiałem to poprawnie, problem polega na tym, że chcesz wyszukać nazwę użytkownika wprowadzoną przez użytkownika w dwóch różnych kolumnach bazy danych.

Oczywiście, możesz to zrobić, dostosowując UserDetailsService.

public class CustomJdbcDaoImpl extends JdbcDaoImpl { 

    @Override 
    protected List<GrantedAuthority> loadUserAuthorities(String username) { 
    return getJdbcTemplate().query(getAuthoritiesByUsernameQuery(), new String[] {username, username}, new RowMapper<GrantedAuthority>() { 
      public GrantedAuthority mapRow(ResultSet rs, int rowNum) throws SQLException { 
       ....... 
      } 
     }); 
    } 

    @Override 
    protected List<UserDetails> loadUsersByUsername(String username) { 
     return getJdbcTemplate().query(getUsersByUsernameQuery(), new String[] {username, username}, new RowMapper<UserDetails>() { 
      public UserDetails mapRow(ResultSet rs, int rowNum) throws SQLException { 
       ....... 
      } 
     }); 
} 

Twoja konfiguracja fasoli dla tej klasy będzie wyglądać mniej więcej tak.

<beans:bean id="customUserDetailsService" class="com.xxx.CustomJdbcDaoImpl"> 
    <beans:property name="dataSource" ref="dataSource"/> 
    <beans:property name="usersByUsernameQuery"> 
     <beans:value> YOUR_QUERY_HERE</beans:value> 
    </beans:property> 
    <beans:property name="authoritiesByUsernameQuery"> 
     <beans:value> YOUR_QUERY_HERE</beans:value> 
    </beans:property> 
</beans:bean> 

Twoje pytania będzie wyglądać podobnie do tego

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

miałem ten sam problem, a po próbie z wielu różnych zapytań, procedur ... ja wykryto, że to działa:

public void configAuthentication(AuthenticationManagerBuilder auth) 
     throws Exception { 
    // Codificación del hash 
    PasswordEncoder pe = new BCryptPasswordEncoder(); 

    String userByMailQuery = "SELECT mail, password, enabled FROM user_ WHERE mail = ?;"; 
    String userByUsernameQuery = "SELECT mail, password, enabled FROM user_ WHERE username=?"; 
    String roleByMailQuery = "SELECT mail, authority FROM role WHERE mail =?;"; 

    auth.jdbcAuthentication().dataSource(dataSource).passwordEncoder(pe) 
      .usersByUsernameQuery(userByMailQuery) 
      .authoritiesByUsernameQuery(roleByMailQuery); 

    auth.jdbcAuthentication().dataSource(dataSource).passwordEncoder(pe) 
      .usersByUsernameQuery(userByUsernameQuery) 
      .authoritiesByUsernameQuery(roleByMailQuery); 

} 

Jego ju st powtórzyć konfigurację za pomocą dwóch zapytań.

Powiązane problemy