У меня есть угловая передняя часть и пружинная защита на заднем конце.
Мой контроллер входа отправляет через POST запрос учетных данных клиента, которые шифруются с использованием алгоритма Base64. Код следующий:
gasStation.controller('LoginController', ['$rootScope', '$scope', '$http', '$window', 'customerInformation',
function ($rootScope, $scope, $http, $window, customerInformation) {
$rootScope.Login = function () {
var encodedData = btoa($scope.username+':'+$scope.password);
$http.defaults.headers.common['Authorization'] = 'Basic ' + encodedData;
$http({
method: 'POST',
url: '/login',
headers: {
"Content-Type": "application/x-www-form-urlencoded",
"X-Ajax-call": 'true'
}
})
.success(function (response) {
})
.error(function (response) {
});
};
}]);
На заднем конце у меня есть следующая конфигурация безопасности Spring:
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
// declare all public resources and URIs
http.authorizeRequests()
.antMatchers("/pages/index.html", "/pages/public/**", "/resources/css/**", "/resources/img/**", "/resources/js/**").permitAll();
http.authorizeRequests().antMatchers("/login", "logout").permitAll();
http.authorizeRequests().antMatchers(HttpMethod.POST, "/register").permitAll();
http.authorizeRequests().antMatchers(HttpMethod.GET, "/customer_types").permitAll();
// any other resources and URIs must pass authentication procedure.
http.httpBasic().and().authorizeRequests().anyRequest().authenticated();
http.formLogin()
.successHandler(new AjaxAuthenticationSuccessHandler(customerRepository))
.failureHandler(new AjaxAuthenticationFailureHandler())
.and()
.logout()
.logoutUrl("/logout")
.logoutSuccessUrl("/pages/index.html");
http.exceptionHandling().authenticationEntryPoint(new AjaxAuthorizationPoint());
}
Если аутентификация прошла успешно, я отправляю обратно файл cookie:
public class AjaxAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
private CustomerRepository customerRepository;
public AjaxAuthenticationSuccessHandler(CustomerRepository customerRepository) {
this.customerRepository = customerRepository;
}
@Override
public void onAuthenticationSuccess(HttpServletRequest request,
HttpServletResponse response,
Authentication authentication) throws IOException, ServletException {
int numberOfEntries;
ObjectMapper objectMapper = new ObjectMapper();
CustomerInformationDto customerInformationDto = new CustomerInformationDto();
Customer customer = customerRepository.getByLogin(authentication.getName());
String customerType = customer.getCustomerType().getTypeName();
if ("REGULAR".equals(customerType)) {
numberOfEntries = customer.getVehicles().size();
} else {
numberOfEntries = customer.getGasstations().size();
}
// create here a cookie and send it back to a client.
customerInformationDto.setStatus("ok");
customerInformationDto.setCustomerType(customer.getCustomerType().getTypeName());
customerInformationDto.setNumberOfEntries(numberOfEntries);
response.getWriter().print(objectMapper.writeValueAsString(customerInformationDto));
saveCookie("my god damn cookie","my god damn cookie",response);
response.getWriter().flush();
}
private void saveCookie(String cookieName, String value, HttpServletResponse response) {
Cookie cookie = new Cookie(cookieName, value);
//maxAge is one month: 30*24*60*60
cookie.setMaxAge(2592000);
response.addCookie(cookie);
}
}
Если что-то не так, я просто отправлю сообщение об ошибке:
public class AjaxAuthenticationFailureHandler implements AuthenticationFailureHandler {
@Override
public void onAuthenticationFailure(HttpServletRequest request,
HttpServletResponse response,
AuthenticationException exception) throws IOException, ServletException {
ObjectMapper objectMapper = new ObjectMapper();
CustomerInformationDto customerInformationDto = new CustomerInformationDto();
customerInformationDto.setStatus("Invalid login or password.");
response.setStatus(403);
response.getWriter().print(objectMapper.writeValueAsString(customerInformationDto));
response.getWriter().flush();
}
}
Однако, если я отправлю действительный логин и пароль, которые зашифрованы с помощью base64, то мой UserDetailsService не сможет найти клиента по его/ее логину, что приведет к ошибке 403.
Возникает вопрос: как Spring декодирует логин и пароль из заголовка авторизации?
Поместите его по-другому, когда я использую следующий код (без base64):
gasStation.controller('LoginController', ['$rootScope', '$scope', '$http', '$window', 'customerInformation',
function ($rootScope, $scope, $http, $window, customerInformation) {
$rootScope.Login = function () {
var postData = 'username=' + $scope.username + '&password=' + $scope.password;
var url = "http://" + $window.location.host + '/pages/index.html#';
$http({
method: 'POST',
url: '/login',
data:postData,
headers: {
"Content-Type": "application/x-www-form-urlencoded",
"X-Ajax-call": 'true'
}
})
.success(function (response) {
})
.error(function (response) {
$scope.errorMessage = response.status;
});
};
}]);
Spring успешно находит пользователя с его/ее именем, но когда я использую шифрование btoa на передней панели, он не делает этого.
Сначала nitpick: Base64 - это алгоритм кодирования, а не шифрование. Но я не думаю, что base64 - проблема, эта часть выглядит отлично.
Проблема в том, что вы используете один и тот же URL-адрес для Basic auth как для входа в форму (/login
). Сначала запрос попадет в UsernamePasswordAuthenticationFilter
, что приведет к сбою аутентификации, поскольку нет данных формы. Заголовок авторизации никогда не проверяется. При выполнении Basic auth против другого пути URL-адреса будет исправлена проблема.
Также обратите внимание, что AuthenticationFailureHandler
предназначен только для входа в форму, он не будет вызываться при правильном использовании Basic auth.
inject the encoder bean in your authentication-manager
? Вы имеете в виду, что я должен автоматически подключать любой кодировщик паролей в моей весенней конфигурации контекста безопасности?