Как защитить REST API с помощью Spring загрузки и Spring безопасности?
Я знаю, что защита REST API широко комментируется, но я не могу создать небольшой прототип, соответствующий моим критериям (и мне нужно подтвердить, что эти критерии реалистичны). Существует так много вариантов, как защитить ресурсы и как работать с безопасностью Spring, мне нужно уточнить, реалистичны ли мои потребности.
Мои требования
- Аутентификатор, основанный на токенах - пользователи предоставят свои учетные данные и получат уникальный токен с ограниченным временем доступа. Я хотел бы управлять созданием токенов, проверкой действительности, истечением срока в моей собственной реализации.
- Некоторые ресурсы REST будут общедоступны - нет необходимости аутентифицироваться вообще,
- Некоторые ресурсы будут доступны только для пользователей с правами администратора,
- Другой ресурс будет доступен после авторизации для всех пользователей.
- Я не хочу использовать обычную проверку подлинности
- Конфигурация кода Java (не XML)
Текущее состояние
Мой REST API работает очень хорошо, но теперь мне нужно его защитить. Когда я искал решение, я создал фильтр javax.servlet.Filter
:
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
String accessToken = request.getHeader(AUTHORIZATION_TOKEN);
Account account = accountDao.find(accessToken);
if (account == null) {
throw new UnauthorizedException();
}
chain.doFilter(req, res);
}
Но это решение с javax.servlet.filters
не работает так, как мне нужно, потому что есть проблема с обработкой исключений через @ControllerAdvice
с Spring servlet dispatcher
.
Что мне нужно
Я хотел бы знать, являются ли эти критерии реалистичными и получить какую-либо помощь, как начать защищать REST API с помощью Spring Security. Я прочитал много учебников (например, Spring Data REST + Spring Безопасность), но все работают в очень простой конфигурации - пользователи с их учетные данные сохраняются в памяти в конфигурации, и мне нужно работать с СУБД и создавать собственный аутентификатор.
Пожалуйста, дайте мне несколько идей о том, как начать.
Ответы
Ответ 1
Аутентификация на основе токена - пользователи предоставят свои учетные данные и уникальный и ограниченный по времени токен доступа. Я хотел бы управлять токеном создание, проверка действительности, истечение срока в моей собственной реализации.
Собственно, используйте Filter for Token Auth - лучший способ в этом случае
В конце концов вы можете создать CRUD через Spring Data для управления свойствами Token, как истек, и т.д.
Вот мой токен-фильтр:
http://pastebin.com/13WWpLq2
И реализация Token Service
http://pastebin.com/dUYM555E
Некоторые ресурсы REST будут общедоступны - нет необходимости аутентифицироваться вообще
Это не проблема, вы можете управлять своими ресурсами через Spring конфигурацию безопасности следующим образом: .antMatchers("/rest/blabla/**").permitAll()
Некоторые ресурсы будут доступны только для пользователей с правами администратора,
Взгляните на @Secured
аннотацию к классу. Пример:
@Controller
@RequestMapping(value = "/adminservice")
@Secured("ROLE_ADMIN")
public class AdminServiceController {
Другой ресурс будет доступен после авторизации для всех пользователей.
Вернуться к Spring Конфигурация безопасности, вы можете настроить свой url следующим образом:
http
.authorizeRequests()
.antMatchers("/openforall/**").permitAll()
.antMatchers("/alsoopen/**").permitAll()
.anyRequest().authenticated()
Я не хочу использовать обычную проверку подлинности
Да, через фильтр токенов ваши пользователи будут аутентифицированы.
Конфигурация кода Java (не XML)
Вернемся к словам выше, посмотрите @EnableWebSecurity
.
Ваш класс будет:
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {}
Вы должны переопределить метод configure. Код ниже, например, как настроить сопоставления. Это из другого проекта.
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/assets/**").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.usernameParameter("j_username")
.passwordParameter("j_password")
.loginPage("/login")
.defaultSuccessUrl("/", true)
.successHandler(customAuthenticationSuccessHandler)
.permitAll()
.and()
.logout()
.logoutUrl("/logout")
.invalidateHttpSession(true)
.logoutSuccessUrl("/")
.deleteCookies("JSESSIONID")
.logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
.and()
.csrf();
}
Ответ 2
Spring безопасность также очень полезна для обеспечения аутентификации и авторизации URL-адресов REST. Нам не нужно указывать какие-либо пользовательские реализации.
Сначала вам нужно указать точку входа-ref для restAuthenticationEntryPoint в вашей конфигурации безопасности, как показано ниже.
<security:http pattern="/api/**" entry-point-ref="restAuthenticationEntryPoint" use-expressions="true" auto-config="true" create-session="stateless" >
<security:intercept-url pattern="/api/userList" access="hasRole('ROLE_USER')"/>
<security:intercept-url pattern="/api/managerList" access="hasRole('ROLE_ADMIN')"/>
<security:custom-filter ref="preAuthFilter" position="PRE_AUTH_FILTER"/>
</security:http>
Реализация для restAuthenticationEntryPoint может быть такой, как показано ниже.
@Component
public class RestAuthenticationEntryPoint implements AuthenticationEntryPoint {
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException ) throws IOException {
response.sendError( HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized" );
}
}
После этого вам нужно указать RequestHeaderAuthenticationFilter. Он содержит ключ RequestHeader. Это в основном используется для идентификации аутентификации пользователя. Обычно RequestHeader передает эту информацию при выполнении вызовов REST.
Например, рассмотрим ниже код
<bean id="preAuthFilter" class="org.springframework.security.web.authentication.preauth.RequestHeaderAuthenticationFilter">
<property name="principalRequestHeader" value="Authorization"/>
<property name="authenticationManager" ref="authenticationManager" />
</bean>
Здесь
<property name="principalRequestHeader" value="Authorization"/>
"Авторизация" - это ключ, представленный входящим запросом. Он содержит требуемую информацию аутентификации пользователя.
Также вам необходимо настроить PreAuthenticatedAuthenticationProvider для выполнения наших требований.
<bean id="preauthAuthProvider" class="org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider">
<property name="preAuthenticatedUserDetailsService">
<bean id="userDetailsServiceWrapper"
class="org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper">
<property name="userDetailsService" ref="authenticationService"/>
</bean>
</property>
</bean>
Этот код будет работать для защиты URL-адресов REST посредством аутентификации и авторизации без каких-либо пользовательских реализаций.
Для полного кода, пожалуйста, найдите ссылку ниже:
https://github.com/srinivas1918/spring-rest-security
Ответ 3
Я тоже искал это долгое время. Я работаю над подобным проектом. Я узнал, что Spring имеет модуль для реализации сеанса через redis. Это выглядит легко и полезно.
Я добавлю также свой проект. Может быть полезно:
http://docs.spring.io/spring-session/docs/1.2.1.BUILD-SNAPSHOT/reference/html5/guides/rest.html
Ответ 4
Чтобы проверить API REST, есть 2 способа
1 - Обычная проверка подлинности с использованием имени пользователя и пароля по умолчанию, заданного в файле application.properties
Основная аутентификация
2 - Аутентификация с использованием базы данных (userDetailsService) с фактическим именем пользователя и паролем
Расширенная аутентификация