Выбрать главу

Для приложения Taco Cloud вы хотите, чтобы клиенты могли регистрироваться в приложении и управлять своими учетными записями пользователей. Это не соответствует ограничениям хранилища пользователей в памяти, поэтому давайте рассмотрим другой вариант, который позволяет использовать хранилище пользователей, поддерживаемое базой данных.

4.2.2 Хранилище пользователей на основе JDBC

Сведения о пользователях часто хранятся в реляционной базе данных, и хранилище пользователей на основе JDBC кажется подходящим. В следующем списке показано, как настроить Spring Security для проверки подлинности сведений о пользователях, хранящихся в реляционной базе данных с помощью JDBC.

Листинг 4.3 Идентификация через JDBC-базу

@Autowired

DataSource dataSource;

@Override

protected void configure(AuthenticationManagerBuilder auth) throws Exception {

 auth.jdbcAuthentication()

   .dataSource(dataSource);

}

Эта реализация configure() вызывает jdbcAuthentication() на данном AuthenticationManagerBuilder. Для этого необходимо установить DataSource, чтобы он знал, как получить доступ к DataSource. DataSource, используемый здесь, обеспечивается магией autowiring.

ПЕРЕОПРЕДЕЛЕНИЕ ПОЛЬЗОВАТЕЛЬСКИХ ЗАПРОСОВ ПО УМОЛЧАНИЮ

Хотя эта минимальная конфигурация будет работать, она делает некоторые предположения о схеме базы данных. Предполагается, что существуют определенные таблицы, в которых будут храниться пользовательские данные. В частности, следующий фрагмент кода из внутренних компонентов Spring Security показывает SQL-запросы, которые будут выполняться при поиске сведений о пользователе:

public static final String DEF_USERS_BY_USERNAME_QUERY =

 "select username,password,enabled " +

 "from users " +

 "where username = ?";

public static final String DEF_AUTHORITIES_BY_USERNAME_QUERY =

 "select username,authority " +

 "from authorities " +

 "where username = ?";

public static final String DEF_GROUP_AUTHORITIES_BY_USERNAME_QUERY =

 "select g.id, g.group_name, ga.authority " +

 "from groups g, group_members gm, group_authorities ga " +

 "where gm.username = ? " +

 "and g.id = ga.group_id " +

 "and g.id = gm.group_id";

Первый запрос извлекает имя пользователя, пароль и информацию о том, включены они или нет. Эта информация используется для аутентификации пользователя. Следующий запрос ищет предоставленные полномочия пользователя для целей авторизации, а последний запрос ищет полномочия, предоставленные пользователю как члену группы.

Если вы согласны с определением и заполнением таблиц в базе данных, удовлетворяющих этим запросам, вам больше нечего делать.  Но, скорее всего, ваша база данных не выглядит так, и вам понадобится больше контроля над запросами. В этом случае можно настроить собственные запросы.

Листинг 4.4 Настройка запросов сведений о пользователе

@Override

protected void configure(AuthenticationManagerBuilder auth) throws Exception {

 auth.jdbcAuthentication()

   .dataSource(dataSource)

   .usersByUsernameQuery(

     "select username, password, enabled from Users " +

     "where username=?")

   .authoritiesByUsernameQuery(

     "select username, authority from UserAuthorities " +

     "where username=?");

}

В этом случае переопределяются только запросы проверки подлинности и обычной авторизации. Но можно также переопределить запрос полномочий группы, вызвав groupAuthoritiesByUsername () с помощью пользовательского запроса.

При замене SQL-запросов по умолчанию, запросами собственной разработки важно придерживаться базового контракта запросов. Все они принимают имя пользователя в качестве единственного параметра. Запрос проверки подлинности выбирает  username, password и enabled. Запрос привилегий выбирает ноль или более строк, содержащих username и authority. Запрос привилегий группы выбирает ноль или более строк, каждая с идентификатором группы, group_name и authority.

РАБОТА С ЗАКОДИРОВАННЫМИ ПАРОЛЯМИ

Сосредоточившись на запросе проверки подлинности, можно увидеть, что пароли пользователей должны храниться в базе данных.  Единственная проблема с этим заключается в том, что если пароли хранятся в текстовом виде, они могут стать доступны для любопытных глаз хакеров. Но если вы закодируете пароли в базе данных, проверка подлинности завершится ошибкой, так как она не будет соответствовать паролю открытого текста, отправленному пользователем.

Для решения этой проблемы, вам нужно указать кодировщик пароля, обратившись к методу passwordEncoder():

@Override

protected void configure(AuthenticationManagerBuilder auth) throws Exception {

 auth.jdbcAuthentication()

   .dataSource(dataSource)

   .usersByUsernameQuery(

     "select username, password, enabled from Users " +

     "where username=?")