【问题标题】:How to create a Spring Interceptor for Spring RESTful web services如何为 Spring RESTful Web 服务创建 Spring 拦截器
【发布时间】:2016-11-16 13:05:04
【问题描述】:

我有一些没有 web.xml 的 Spring RESTful (RestControllers) Web 服务,我正在使用 Spring boot 来启动这些服务。

我想为 Web 服务添加授权层,并希望在实际调用 Web 服务本身之前将所有 http 请求路由到一个前端控制器。 (我有一个代码可以在授权层模拟会话行为,以根据我与客户端的每个 httpRequest 一起发送的生成的密钥来验证用户)。

是否有任何标准 Spring 解决方案将所有请求路由到过滤器/前端控制器?

提前致谢, 普兰尼斯

编辑: 添加我的代码

控制器: `

@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 {
}

`

【问题讨论】:

  • 在请求头中设置tocken或ID并验证。

标签: spring-mvc spring-restcontroller spring-rest


【解决方案1】:

春季 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);
  }
}

【讨论】:

    【解决方案2】:

    此类事情有一个默认解决方案。 春季安全。你只需要实现类似的东西:

    @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>
    

    【讨论】:

      【解决方案3】:

      可以采取以下步骤来使用 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";
            }
        }
        

      【讨论】:

      • 你怎么知道你得到了一个HandlerMethod 传递给你的LoginInterceptor?
      • WebMvcConfigurerAdapter 现在已弃用。改为实现WebMvcConfigurer。
      • 这对我帮助很大。谢谢。
      【解决方案4】:

      你应该添加这个来注册你的拦截器

      @Configuration
      public class MyConfiguration extends WebMvcConfigurerAdapter {
      
          @Bean
          AuthenticationInterceptor getAuthenticationInterceptor() {
              return new AuthenticationInterceptor();
          }
      
          @Override
          public void addInterceptors (InterceptorRegistry registry) {
              registry.addInterceptor(getAuthenticationInterceptor());
      
          }
      }
      

      【讨论】:

      • @Component public class LoginInterceptor extends HandlerInterceptorAdapter{ ....} 即在 LoginInterceptor 上添加组件注释对我有帮助
      【解决方案5】:

      这里是拦截器的一个例子:

      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() {
         ...
      }
      

      这只是给您一个想法的模板/示例。 我希望这会对你有所帮助。

      【讨论】:

      • 您好,Pracede,感谢您的回复。但这似乎不起作用。我们不应该在某些地方指定正在使用拦截器(如任何注释或任何 xml 文件)。我已经实现了上述逻辑,但没有工作。我已在问题的编辑空间中附加了我的代码。如果您能在这方面帮助我,我将非常感谢您
      • @PraneethReddy 您需要覆盖WebMvcConfigurer 中的addInterceptors 方法。还要用 @Configuration 注释你的类
      • 如果加了拦截器,注释的意义何在?
      猜你喜欢
      • 1970-01-01
      • 2012-11-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-10-25
      • 1970-01-01
      • 2011-08-29
      • 2018-08-09
      相关资源
      最近更新 更多