Как вернуть HTTP 403 после успешной аутентификации, но неудачной авторизации?JAVA

Программисты JAVA общаются здесь
Ответить
Anonymous
 Как вернуть HTTP 403 после успешной аутентификации, но неудачной авторизации?

Сообщение Anonymous »

У меня есть приложение Spring Boot, которое также использует Spring Security. Я хочу проверить, есть ли у пользователя доступ для входа в приложение, но это должно быть после аутентификации. Суть в том, что при входе пользователь выбирает проект, к которому ему необходимо подключиться. Пользователю может быть разрешено подключение к одному проекту, но не разрешено подключение к другому проекту. Однако, если пользователь вводит неверные учетные данные, сначала должно отображаться сообщение о неверных учетных данных, даже если у пользователя нет права входа в выбранный проект. По этой причине проверка прав на проект должна быть после аутентификации.
Это мой класс SecurityConfig:

Код: Выделить всё

package org.aze.accountingprogram.config;

import org.aze.accountingprogram.models.CurrentUser;
import org.aze.accountingprogram.models.PermissionAliasConstants;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.authentication.encoding.Md5PasswordEncoder;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

private static final Logger logger = LoggerFactory.getLogger(SecurityConfig.class);

@Autowired
private UserDetailsService userDetailsService;

@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests().antMatchers("/lib/**").permitAll().anyRequest().fullyAuthenticated()
.and()
.formLogin().successHandler(successHandler()).loginPage("/login").permitAll()
.and().exceptionHandling().accessDeniedHandler(accessDeniedHandler())
.and()
.logout().logoutUrl("/logout").logoutSuccessUrl("/login").permitAll();

http.csrf().disable();
}

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(new Md5PasswordEncoder());
}

private AccessDeniedHandler accessDeniedHandler() {
return (request, response, e) -> {
logger.debug("Returning HTTP 403 FORBIDDEN with message: \"{}\"", e.getMessage());
response.sendError(HttpStatus.FORBIDDEN.value(), e.getMessage());
};
}

private AuthenticationSuccessHandler successHandler() {
return new AuthenticationSuccessHandler() {
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
CurrentUser user = (CurrentUser) authentication.getPrincipal();
if (!user.hasAccessRight(PermissionAliasConstants.LOGIN)) {
throw new AccessDeniedException(String.format("User \"%s\" is not authorized to login \"%s\"  project", user.getUsername(), user.getProject().getName()));
}
}
};
}

}
реализация UserDetailsService:

Код: Выделить всё

package org.aze.accountingprogram.serviceimpl;

import org.aze.accountingprogram.common.Constants;
import org.aze.accountingprogram.exceptions.DataNotFoundException;
import org.aze.accountingprogram.models.AccessRightsPermission;
import org.aze.accountingprogram.models.CurrentUser;
import org.aze.accountingprogram.models.Project;
import org.aze.accountingprogram.models.User;
import org.aze.accountingprogram.service.AccessRightsService;
import org.aze.accountingprogram.service.ProjectService;
import org.aze.accountingprogram.service.UserService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

@Service
public class UserDetailsServiceImpl implements UserDetailsService {

@Autowired
private UserService userService;

@Autowired
private ProjectService projectService;

@Autowired
private AccessRightsService accessRightsService;

@Autowired
private HttpServletRequest request;

private static final Logger logger = LoggerFactory.getLogger(UserDetailsServiceImpl.class);

@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user;
Project project;
final String projectId = request.getParameter(Constants.SESSION_PROJECT_ID);
logger.debug("Username: {}, projectId: {}", username, projectId);

try {
user = userService.getUserByUsername(username);
} catch (DataNotFoundException e) {
throw new UsernameNotFoundException(e.getMessage(), e);
}

// Value of projectId is from combo box which is filled from table of projects
// That is why there is no probability that the project will not be found
project = projectService.getProjectById(Integer.valueOf(projectId));

// User can have different rights for different projects
List accessRights = accessRightsService.getAccessRightsByProject(user.getId(), project.getId());
Set authorities = new HashSet(accessRights.size());
authorities.addAll(accessRights.stream().map(right -> new SimpleGrantedAuthority(right.getAlias())).collect(Collectors.toList()));

final CurrentUser currentUser = new CurrentUser(user, project, authorities);

// If to check LOGIN access right to project here, and user entered right credentials
// then user will see message about invalid credentials.
// .and().exceptionHandling().accessDeniedHandler(accessDeniedHandler()) at SecurityConfig is not working in this case
//        if (!currentUser.hasAccessRight(PermissionAliasConstants.LOGIN)) {
//            throw new AccessDeniedException(String.format("User \"%s\" is not authorized to login \"%s\" project", user.getUsername(), project.getName()));
//        }

logger.info("Logged in user: {}", currentUser);
return currentUser;
}
}
и LoginController

Код: Выделить всё

package org.aze.accountingprogram.controllers;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;

import java.util.Optional;

@Controller
public class LoginController {

@RequestMapping(value = "/login", method = RequestMethod.GET)
public ModelAndView getLoginPage(@RequestParam Optional  error) {
return new ModelAndView("login", "error", error);
}

}

Код: Выделить всё

successHandler()
работает, и приложение выдает исключение AccessDeniedException, если у пользователя нет права доступа для входа в проект. Но accessDeniedHandler() не работает и не отправляет HTTP 403. Вместо этого я получаю HTTP 500.
Как вернуть ответ с HTTP 403 и сообщением об исключении (например, «Пользователь «tural» не авторизован для входа в проект «AZB») и обработать его в LoginController (используя @ResponseStatus(HttpStatus.FORBIDDEN) или @ExceptionHandler)?

Подробнее здесь: https://stackoverflow.com/questions/364 ... ul-authori
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «JAVA»