#angular #spring #spring-boot #spring-security
#angular #spring #spring-boot #spring-security
Вопрос:
Я пытаюсь реализовать реализацию токена CSRF на основе Spring Security и Angular 4. Первоначальная аутентификация для моего приложения использует страницу единого входа организации. Сообщение, которое мы перенаправляем на домашнюю страницу приложения. Ниже приведена моя реализация WebSecurityConfigurerAdapter с использованием 2 уровней фильтров, 1 для проверки и добавления токена CSRF, другой — для целей внутренней аутентификации приложений для обеспечения безопасности на уровне метода с использованием @Secured.
@Configuration
@EnableWebSecurity
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
private static final Logger LOGGER = LoggerFactory.getLogger(WebSecurityConfiguration.class);
@Autowired
private CustomAuthenticationProviderService authenticationProviderService;
public static final String CSRF_COOKIE_NAME = "XSRF-TOKEN";
private static final String[] CSRF_IGNORE = { ""};
private static final String CSRF_HEADER_NAME = "X-XSRF-TOKEN";
@Component
@Order(1)
public class CustomCsrfFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
CsrfToken csrf = (CsrfToken) request.getAttribute(CsrfToken.class.getName());
if (csrf != null) {
Cookie cookie = WebUtils.getCookie(request, CSRF_COOKIE_NAME);
String token = csrf.getToken();
if (cookie == null || token != null amp;amp; !token.equals(cookie.getValue())) {
cookie = new Cookie(CSRF_COOKIE_NAME, token);
cookie.setPath("/");
cookie.setHttpOnly(false);
response.addCookie(cookie);
}
}
filterChain.doFilter(request, response);
}
}
@Bean
@Order(2)
public FilterRegistrationBean createFilterRegistrationBean() {
FilterRegistrationBean registration = new FilterRegistrationBean(new OncePerRequestFilter() {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
try {
// App method specific authentication code
return;
}
} catch (AuthenticationException e) {
LOGGER.error("Authentication error", e);
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
response.sendRedirect("/error/unauthorized.html");
return;
}
}
@Override
protected boolean shouldNotFilter(HttpServletRequest request) throws ServletException {
String uri = request.getRequestURI();
return uri.startsWith("/resources/") || uri.startsWith("/static/") || uri.startsWith("/css/")
|| uri.startsWith("/images/") || uri.startsWith("/js/") || uri.startsWith("/api/tct/")
|| uri.startsWith("/api/unit/unitConversion");
}
});
return registration;
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.httpBasic()
.and().csrf() // csrf config starts here
.ignoringAntMatchers(CSRF_IGNORE) // URI where CSRF check will not be applied
.csrfTokenRepository(csrfTokenRepository()) // defines a repository where tokens are stored
.and().addFilterAfter(new CustomCsrfFilter(), CsrfFilter.class)
; // Csrf filter in
// which we will add
// the cookie
}
private CsrfTokenRepository csrfTokenRepository() {
CookieCsrfTokenRepository tokenRepository = CookieCsrfTokenRepository.withHttpOnlyFalse();
tokenRepository.setCookiePath("/");
return tokenRepository;
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(authenticationProviderService);
}
}
вот мой код в Angular для встраивания токена CSRF:
поставщики модуля приложения
{
provide: HTTP_INTERCEPTORS,
useClass: MyHttpInterceptor,
multi: true
}
custom interceptor to append cookies:
import { Injectable } from "@angular/core";
import { tap } from "rxjs/operators";
import {
HttpRequest,
HttpHandler,
HttpEvent,
HttpInterceptor,
HttpResponse,
HttpErrorResponse
} from "@angular/common/http";
import { Observable } from "rxjs/Observable";
@Injectable()
export class MyHttpInterceptor implements HttpInterceptor {
constructor() { }
//function which will be called for all http calls
intercept(
request: HttpRequest<any>,
next: HttpHandler
): Observable<HttpEvent<any>> {
let requestToForward = request;
let token = getCookie("XSRF-TOKEN");
if (token != null) {
requestToForward = request.clone(
{ setHeaders: { 'XSRF-TOKEN': token } });
}
return next.handle(requestToForward);
}
}
function getCookie(name: String) {
const splitCookie = document.cookie.split(';');
for (let i = 0; i < splitCookie.length; i ) {
const splitValue = splitCookie[i].split('=');
if (splitValue[0] === name) {
return splitValue[1];
}
}
return '';
}
Итак, я получаю это всплывающее окно при нескольких POST-запросах имени пользователя и пароля. Поскольку я внедрил пользовательскую аутентификацию, я не полагаюсь на ввод, предоставленный в этой форме по умолчанию для моей проверки, и, по сути, просто нужно нажать «Войти», когда он появится, не предоставляя никаких подробностей. Я бы хотел удалить это всплывающее окно, поскольку оно действительно не имеет никакой цели быть там.
Заранее спасибо.
Комментарии:
1. внедрение пользовательской безопасности — плохая практика.
2. @Thomas Мне не нужна вся часть аутентификации / авторизации, но мне нужна только реализация CSRF. Я попытался отключить http Basic через appllication. yml от security.basic.enabled: false, но этого тоже не удалось достичь.
3. Если вы не можете отключить его, вы делаете это неправильно. Проверьте официальную документацию. Все это там.
4. @Thomas Я считаю, что это больше связано с пользовательской реализацией, связанной с версией spring security, которую я использую. Проект основан на Spring Boot 1.7, и, следовательно, обновление до одной из более новых версий приведет к сбою многих функций. Было бы очень полезно, если бы вы могли поделиться некоторыми ссылками на документацию для той же версии.
5. У меня нет никаких ссылок на документацию о чем-то таком старом. Удачи