Как создать перехватчик Spring для Spring веб-служб RESTful
У меня есть несколько веб-сервисов Spring RESTful (RestControllers) без web.xml, и я использую загрузку Spring для запуска служб.
Я хочу добавить уровень авторизации для веб-сервисов и хочу перенаправить все HTTP-запросы на один фронт-контроллер, прежде чем фактически вызвать веб-сервис. (У меня есть код для имитации поведения сеансов на уровне аутрификации, чтобы проверить пользователя на основе сгенерированного ключа, который я отправляю с каждым из httpRequest от клиента).
Есть ли какое-либо стандартное решение Spring при маршрутизации всех запросов на фильтр/фронт-контроллер?
Спасибо заранее,
Praneeth
Изменить:
Добавление моего кода
контроллер:
`
@RestController
public class UserService {
UserDAO userDAO = new UserDAO();
@RequestMapping(value="/login", method = RequestMethod.POST)
@LoginRequired
public String login(@RequestParam(value="user_name") String userName, @RequestParam(value="password") String password, HttpServletRequest request){
return userDAO.login(userName, password);
}
}`
перехватчик:
`
public class AuthenticationInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
System.out.println("In Interceptor");
//return super.preHandle(request, response, handler);
return true;
}
@Override
public void postHandle( HttpServletRequest request, HttpServletResponse response,
Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("---method executed---");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
Object handler, Exception ex) throws Exception {
System.out.println("---Request Completed---");
}
}
`
интерфейс.
`
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface LoginRequired {
}
`
Ответы
Ответ 1
Следующие шаги могут быть предприняты для реализации перехватчика с помощью Spring:
-
Внедрение класса перехватчика, расширяющего класс HandlerInterceptorAdapter. Вот как выглядит код:
public class LoginInterceptor extends HandlerInterceptorAdapter {
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception exception)
throws Exception {
// TODO Auto-generated method stub
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
throws Exception {
// TODO Auto-generated method stub
}
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
HandlerMethod handlerMethod = (HandlerMethod) handler;
String emailAddress = request.getParameter("emailaddress");
String password = request.getParameter("password");
if(StringUtils.isEmpty(emailAddress) || StringUtils.containsWhitespace(emailAddress) ||
StringUtils.isEmpty(password) || StringUtils.containsWhitespace(password)) {
throw new Exception("Invalid User Id or Password. Please try again.");
}
return true;
}
}
-
Внедрить класс AppConfig или добавить addInterceptors в один из существующих классов конфигурации. Обратите внимание на шаблон пути, указанный в экземпляре LoginInterceptor
@Configuration
public class AppConfig extends WebMvcConfigurerAdapter {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LoginInterceptor()).addPathPatterns("/account/login");
}
}
-
Внедрите метод контроллера, например:
@Controller
@RequestMapping("/account/login")
public class LoginController {
@RequestMapping(method = RequestMethod.GET)
public String login() {
return "login";
}
}
Ответ 2
здесь пример Interceptor:
public class AuthenticationInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
HandlerMethod handlerMethod = (HandlerMethod) handler;
LoginRequired loginRequired = handlerMethod.getMethod().getAnnotation(LoginRequired.class);
if (loginRequired == null) {
return true;
}
String token = httpServletRequest.getParameter("token");
if (StringUtils.isBlank(token)) {
throw new MissingParameterException();
}
authenticationService.checkToken(token);
return super.preHandle(httpServletRequest, httpServletResponse, handler);
}
@Override
public void postHandle( HttpServletRequest request, HttpServletResponse response,
Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("---method executed---");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
Object handler, Exception ex) throws Exception {
System.out.println("---Request Completed---");
}
Мы можем создать аннотацию:
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface LoginRequired {
}
И затем на контроллере мы получили эту аннотацию:
@RequestMapping(value = "/protected/controller")
@LoginRequired
public ResponseEntity<BaseResponse> controller() {
...
}
Это просто шаблон/пример, чтобы дать вам представление.
Надеюсь, это поможет вам.
Ответ 3
Для таких вещей есть решение по умолчанию.
spring безопасности. И вам просто нужно реализовать что-то вроде:
@Configuration
@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsService userDetailsService;
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.formLogin()
.loginPage("/login")
.failureUrl("/login?error")
.usernameParameter("email")
.permitAll()
.and()
.logout()
.logoutUrl("/logout")
.logoutSuccessUrl("/")
.permitAll();
}
@Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.userDetailsService(userDetailsService)
.passwordEncoder(new BCryptPasswordEncoder());
}
}
зависимость для него:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
Ответ 4
Вы должны добавить это в regsiter ваш перехватчик
@Configuration
public class MyConfiguration extends WebMvcConfigurerAdapter {
@Bean
AuthenticationInterceptor getAuthenticationInterceptor() {
return new AuthenticationInterceptor();
}
@Override
public void addInterceptors (InterceptorRegistry registry) {
registry.addInterceptor(getAuthenticationInterceptor());
}
}
Ответ 5
После весны 5:
Реализация должна быть такой: у нас должен быть класс, который реализует
HandlerInterceptor
public class CustomInterceptor implements HandlerInterceptorr{
}
Затем мы можем зарегистрировать этот перехватчик с помощью класса, который реализует WebMvcConfigurer
и переопределить метод addInterceptors
public class ServiceInterceptorAppConfig implements WebMvcConfigurer {
@Autowired
CustomInterceptor customInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(customInterceptor);
}
}
Ответ 6
Стандартный способ - реализовать Spring Security.
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter
{
@Autowired
private UserDetailsService userDetailsService;
@Override
protected void configure(HttpSecurity http) throws Exception
{
http.csrf().disable();
// The pages does not require login
http.authorizeRequests().antMatchers("/", "/login", "/logout").permitAll();
http
.cors().and()
.httpBasic()
.and()
.authorizeRequests()
.antMatchers("/*", "/api/login/login", "/api/login/signUp",
"/api/login/resendVerificationEmail", "/api/login/sendPasswordResetEmail").permitAll()
.antMatchers("/db/**").access("hasRole('ADMIN') and hasRole('DBA')")
.antMatchers("/users/**").hasRole("USER")//USER role can access /users/**
.antMatchers("/admin/**").hasRole("ADMIN")//ADMIN role can access /admin/**
.antMatchers("/quests/**").permitAll()// anyone can access /quests/**
.anyRequest().authenticated()
.and()
.logout()
.logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
.invalidateHttpSession(true)
.logoutSuccessUrl("/api/user/logoutSuccess")
.permitAll()
.and()
.sessionManagement()
.sessionFixation()
.migrateSession()
.maximumSessions(1)
.expiredUrl("/sessionExpired.html")
.maxSessionsPreventsLogin(false);
}
Таким образом, все остальные запросы с отсутствием соответствия будут автоматически аутентифицированы и отправлены 401 код ошибки, если нет. Это довольно легко.