2017-02-13 23 views
-1

Я исследовал сеть довольно много, но все еще не могу найти решение моей проблемы. Повсюду люди используют вещи, которые не подходят моему делу. Мой scenerio:Весна безопасности - значения считывания от контроллера

пользователь отправляет сообщение {email: "admin", password: "admin"}, тогда есть контроллер входа, который проверяет правильность ввода и после того, как этот токен возвращается в заголовке/теле.

Я застрял в той части, где передаю значения от контроллера к проверке подлинности Spring.

Ниже мой конфиг:

@Configuration 
@EnableWebSecurity 
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true) 
public class WebSecurityConfig extends WebSecurityConfigurerAdapter { 


    @Autowired 
    private TokenAuthenticationProvider tokenAuthenticationProvider; 


    @Autowired 
    @Override 
    protected void configure(AuthenticationManagerBuilder auth) throws Exception { 
     auth.authenticationProvider(this.tokenAuthenticationProvider); 
    } 

    @Override 
    protected void configure(HttpSecurity http) throws Exception { 
     http 
       .authorizeRequests() 
       .antMatchers("/login").permitAll() 
       .anyRequest().authenticated().and() 
       .csrf().disable(); 
    } 
} 

вот мой контроллер:

@RestController 
public class LoginController { 

    @Autowired 
    private AuthenticationManager authenticationManager; 

    @RequestMapping(value = "/login", method = RequestMethod.POST) 
    public ResponseEntity<?> login(@RequestBody LoginCredentials payload){ 

     Authentication authentication = this.authenticationManager.authenticate(
       new UsernamePasswordAuthenticationToken(
         payload.getUsername(), 
         payload.getPassword() 
       ) 
     ); 

     SecurityContextHolder.getContext().setAuthentication(authentication); 
     return ResponseEntity.ok("OK"); 
    } 
} 

и это мой провайдер аутентификации

@Component 
public class TokenAuthenticationProvider implements AuthenticationProvider { 


    @Override 
    public Authentication authenticate(Authentication authentication) throws AuthenticationException { 

     if(authentication.getName().equals("admin") && authentication.getCredentials().equals("admin")) { 
      List<GrantedAuthority> grantedAuths = new ArrayList<>(); 
      grantedAuths.add(new SimpleGrantedAuthority("ROLE_USER")); 
      grantedAuths.add(new SimpleGrantedAuthority("ROLE_ADMIN")); 
      return new UsernamePasswordAuthenticationToken(authentication.getName(), authentication.getCredentials(), grantedAuths); 
     } else { 
      return null; 
     } 
    } 

    @Override 
    public boolean supports(Class<? extends Object> authentication) { 
     return (UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication)); 
    } 
} 

Im делает запрос пост с учетными данными, и это ответ Im получение:

{ 
    "timestamp": 1486995388844, 
    "status": 403, 
    "error": "Forbidden", 
    "exception": "org.springframework.security.authentication.ProviderNotFoundException", 
    "message": "Access Denied", 
    "path": "/login" 
} 
+4

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

+0

@ M.Deinum. Вам нужно обработать входящие учетные данные в фильтре, создать не прошедшую проверку подлинности аутентификацию, которая затем обрабатывается AuthenticationManager, которая разрешает роли и создает авторизацию zed Аутентификация и возвращает токен. При последующих запросах токен разрешается против вашего TokenStore (db) внутри другого фильтра, и вы создаете авторизованную аутентификацию (если токен действителен) и устанавливаете 'SecurityContextHolder.getContext(). SetAuthentication' (как и Spring security в BasicAuthenticationFilter). –

+0

ok Итак, мне нужно 2 фильтра, один проверяет правильность ввода логина (имя пользователя, пароль), и если да, то выдаёт действительный токен (который может быть сохранен в db или просто JWT), а затем я должен написать другой фильтр, который проверяет запросы с прикрепленным токеном? – filemonczyk

ответ

2

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

Я считаю, что вам не нужен этот контроллер: вам просто нужна дополнительная настройка для вашего контейнера безопасности, так что давайте начнем!

BTW: Даже если конфигурация Spring в основном написана на Java, конфигурация Spring Security еще не поддерживает полную Java и по-прежнему должна быть XML по большей части.

Вы можете настроить Spring Security для инициализации процесса аутентификации при ударе определенной конечной точки (с запросом HTTP POST). В XML, это делается следующим образом:

<http> 
    <form-login login-processing-url="/perform_login"/> 

    ...(other configuration) 
</http> 

Хотя я пытался найти его в documentation, я не могу найти эквивалент Java конфигурации. Мы можем вызвать метод formLogin() на HttpSecurity объекта, как это:

protected void configure(HttpSecurity http) throws Exception { 
    http 
    .authorizeRequests() 
     .anyRequest().authenticated() 
     .and() 
    .formLogin() 
     .loginPage("/login") 
     .permitAll(); 
} 

но, кажется, нет никакого метода Java для настройки URL обработки Логин. Метод loginPage() просто указывает URL-адрес для отправки пользователям, если требуется вход в систему (это не то, что мы ищем).

Если вы не настроите URL-адрес для входа в систему, в контейнере безопасности будет использоваться значение по умолчанию: /j_spring_security_check.

Итак, теперь мы можем отправить наши учетные данные для аутентификации в /perform_login, а Spring Security будет использовать их против своих фильтров проверки подлинности, чтобы предоставить вам доступ (или нет).

Готовы ли мы? Еще нет. По умолчанию параметры username и password называются j_username и j_password, поэтому для получения желаемого результата вам необходимо ПОСТУПИТЬ их до /perform_login. К счастью, мы можем настроить имя этих двух (в XML снова - извините):

<http> 
    <form-login login-processing-url="/perform_login"/> 
       username-parameter="email" 
       password-parameter="password" 

    ...(other configuration) 
</http> 

Теперь мы настроены! Выдавая HTTP POST с двумя параметрами (или больше, если вы хотите токены CSRF), а именно , по электронной почте и пароль до /perform_login, мы можем пройти аутентификацию должным образом (и нам не нужно было создать еще один класс под названием LoginCredentials

+0

спасибо за ответ, но я не хочу перенаправлять на пользовательскую страницу входа или что-то в этом роде. Я ожидаю, что пользователь войдет в систему с использованием заданной конечной точки, если они будут в порядке, тогда он получит токен для дальнейшего запроса, если он не получит 401. – filemonczyk

+0

Я боюсь, что я не следую: просто установите URL-адрес для обработки входа в качестве нужной конечной точки, и POST ваши данные там (параметр электронной почты и параметр пароля). –

+0

Я считаю, что вы неправильно поняли эффект, который имеет тег URL-адреса для входа в систему: он не перенаправляет вас на эту страницу, но указывает, что запрос POST на эту страницу инициализирует процесс аутентификации. –