Как создать перехватчик 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 код ошибки, если нет. Это довольно легко.