Войти автоматически с помощью Grails Spring Безопасность

Приложение My Grails использует плагин Spring Security. Мне нужно логически войти в систему пользователя, и у меня нет доступа к их паролю. Я попробовал следующее, которое предположительно работало при использовании плагина Acegi (предка плагина Spring Security):

// automatically login a user and assign them the USER role. 
// In my app, the email address is also the username
GrantedAuthority[] auths = [new GrantedAuthorityImpl('USER')]
SecurityContextHolder.context.authentication 
        = new UsernamePasswordAuthenticationToken(email, 'unknown', auths)

Кажется, что это почти сработало, потому что, если я вызову springSecurityService.principal после выполнения вышеописанного, я верну адрес электронной почты автоматически зарегистрированного пользователя. Однако, если я вызываю springSecurityService.currentUser, я получаю сообщение об ошибке. Коренной причиной этой ошибки является то, что:

SpringSecurityUtils.securityConfig.userLookup.userDomainClassName

возвращает "Лицо", которое не является именем моего пользовательского класса. Различные теги, такие как <sec:loggedInUser>, также не работают, по-видимому, по той же причине.

Интересно, связана ли эта проблема с тем, что я использую ранее существовавшие классы домена для пользователя и роли (а не классы, созданные плагином )? Если пользователь входит в систему, введя свое имя пользователя и пароль в форму (а не программно), все работает нормально.

Update

Следуя советам Burt, я заменил код выше:

springSecurityService.reauthenticate(email)

Но я все еще получаю ошибку на этих строках в пределах SpringSecurityService.getCurrentUser()

String className = SpringSecurityUtils.securityConfig.userLookup.userDomainClassName
grailsApplication.getClassForName(className).get(principal.id)

Потому что className установлен на "Person", а не на имя моего класса User.

Ответы

Ответ 1

Если пользователь существует в базе данных, используйте springSecurityService.reauthenticate() - см. Эту ссылку для Grails 2 или эту ссылку для Grails 3.

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

Ответ 2

Возможно, этот снимок кода из webapp, который я написал, поможет. Мы должны были использовать пользователей с использованием RESTful API, и они предоставили имя пользователя и ключ API. Ключевой частью этого кода является настройка полномочий и аутентифицированных логических значений.

class CustomAppTokenAuthenticationProvider implements AuthenticationProvider {

  def userDetailsService

  Authentication authenticate(Authentication customAuth) {
    def userDetails = userDetailsService.loadUserByUsername(customAuth.principal)
    def user = User.get(userDetails.id)
    if (user?.apiKey.equals(customAuth.credentials)) {
      customAuth.authorities = userDetails.authorities
      customAuth.authenticated = true
      return customAuth
    } else {
      return customAuth
    }
  }

  boolean supports(Class authentication) {
    return CustomAppTokenAuthentication.class.isAssignableFrom(authentication)
  }
}

И вот код из фильтра, который перехватывает вызовы API для обработки аутентификации

    def userId = request.getHeader("x-user-external-id")
    def apiKey = request.getHeader("x-user-api-key")
    if (userId && apiKey) {
      def user = User.findByExternalId(userId)

      def myAuth = new CustomAppTokenAuthentication(
              name: userId,
              credentials: apiKey,
              principal: user.username,
              authenticated: false
      )

      def auth = authenticationManager.authenticate(myAuth);
      if (auth?.authorities?.size() >= 0) {
        log.info "Successfully Authenticated ${userId} in object ${auth}"
        // Store to SecurityContextHolder
        SecurityContextHolder.getContext().setAuthentication(myAuth);
      } else {
        SecurityContextHolder.getContext().setAuthentication(null)
      }

Ответ 3

Метод reauthenticate() имеет два ограничения:

  • Не проверять пароль
  • Это не вызывает события. Вот почему многие плагины, которые прослушивают события, могут не работать. Например плагин для грубой силы.