我尝试通过HandlerInterceptorAdapter记录所有http请求:
public class LogRequestInterceptor extends HandlerInterceptorAdapter {
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
log.debug("afterConcurrentHandlingStarted: {}", request.getRequestURI());
return true;
}
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
log.debug("postHandle: {}", request.getRequestURI());
}
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
log.debug("afterCompletion: {}", request.getRequestURI());
}
public void afterConcurrentHandlingStarted(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
log.debug("afterConcurrentHandlingStarted: {}", request.getRequestURI());
}
}
当我由授权用户请求/ api / videos / free和/ api / members(方法获取)时,一切正常:
2019-04-11 23:21:35.372 DEBUG PopovDesktopLinux --- [nio-8080-exec-2] c.h.v.b.m.LogRequestInterceptor : afterConcurrentHandlingStarted: /api/videos/free
2019-04-11 23:21:35.611 DEBUG PopovDesktopLinux --- [nio-8080-exec-2] c.h.v.b.m.LogRequestInterceptor : postHandle: /api/videos/free
2019-04-11 23:21:35.611 DEBUG PopovDesktopLinux --- [nio-8080-exec-2] c.h.v.b.m.LogRequestInterceptor : afterCompletion: /api/videos/free
2019-04-11 23:21:37.167 DEBUG PopovDesktopLinux --- [nio-8080-exec-1] c.h.v.b.m.LogRequestInterceptor : afterConcurrentHandlingStarted: /api/members
2019-04-11 23:21:37.189 DEBUG PopovDesktopLinux --- [nio-8080-exec-1] c.h.v.b.m.LogRequestInterceptor : postHandle: /api/members
2019-04-11 23:21:37.189 DEBUG PopovDesktopLinux --- [nio-8080-exec-1] c.h.v.b.m.LogRequestInterceptor : afterCompletion: /api/members
如果我通过匿名提出相同的请求,则日志看起来如下:
2019-04-11 23:22:05.813 DEBUG PopovDesktopLinux --- [nio-8080-exec-3] c.h.v.b.m.LogRequestInterceptor : afterConcurrentHandlingStarted: /api/videos/free
2019-04-11 23:22:05.820 DEBUG PopovDesktopLinux --- [nio-8080-exec-3] c.h.v.b.m.LogRequestInterceptor : afterCompletion: /api/videos/free
/ api / videos / free和/ api / members非常相似:
@Log4j2
@RestController
@RequestMapping("/api/members")
public class MemberController {
@PreAuthorize("hasRole('ADMIN')")
@Transactional
@RequestMapping(method = RequestMethod.GET)
public List<com.helan.videoafisha.dto.general.Member> list() {
return modelMapper.map(
memberRepository.findAll(),
new TypeToken<List<com.helan.videoafisha.dto.general.Member>>(){}.getType()
);
}
}
@Log4j2
@RestController
@RequestMapping("/api/videos")
public class VideoController {
@PreAuthorize("hasAnyRole('DEVICE', 'ADMIN')")
@Transactional
@RequestMapping(value = "/free", method = RequestMethod.GET)
public List<com.helan.videoafisha.dto.backend.frontend.admin.videos.free.FreeVideo> freeVideos() {
return modelMapper.map(
freeVideoRepository.findAllWithVideo(),
new TypeToken<List<com.helan.videoafisha.dto.backend.frontend.admin.videos.free.FreeVideo>>(){}.getType()
);
}
}
负责身份验证的代码:
@Log4j2
@Service
public class TokenAuthenticationFilter extends OncePerRequestFilter {
@Autowired
private TokenUtil tokenUtil;
@Autowired
private UserDetailsService memberUserDetailsService;
@Autowired
private UserDetailsService deviceUserDetailsService;
@Value("${mvc.header.token}")
private String tokenHeader;
@Override
protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {
final String tokenString = httpServletRequest.getHeader(tokenHeader);
try {
if (tokenString != null && !tokenString.equals("")) {
Token token = tokenUtil.parseToken(tokenString);
UserDetails userDetails = null;
switch (token.getAuthenticateTarget()) {
case Member: userDetails = memberUserDetailsService.loadUserByUsername(token.getUsername()); break;
case Device: userDetails = deviceUserDetailsService.loadUserByUsername(token.getUsername()); break;
default: log.error(String.format("Unknown authentication target: %s", token.getAuthenticateTarget().toString()));
}
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(token.getUsername(), null, userDetails.getAuthorities());
authenticationToken.setDetails(userDetails);
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
}
} catch (TokenException | UsernameNotFoundException e) {
log.debug(String.format("%s, %s", httpServletRequest.getRequestURI(), e.getLocalizedMessage()));
}
filterChain.doFilter(httpServletRequest, httpServletResponse);
}
}
添加拦截器:
@Configuration
public class MvcConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(logRequestInterceptor).addPathPatterns("/api/**");
}
}
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
TokenAuthenticationFilter tokenAuthenticationFilter;
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.exceptionHandling().authenticationEntryPoint(http403ForbiddenEntryPoint()).and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.authorizeRequests()
.antMatchers("/api/devices/authenticate").permitAll()
.antMatchers("/api/members/authenticate").permitAll()
.antMatchers("/api/*").authenticated().and()
.addFilterBefore(tokenAuthenticationFilter, UsernamePasswordAuthenticationFilter.class)
.headers().frameOptions().sameOrigin().cacheControl();
}
@Bean
protected PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder(11);
}
@Bean
protected Http403ForbiddenEntryPoint http403ForbiddenEntryPoint() {
return new Http403ForbiddenEntryPoint();
}
}
为什么/ api / videos / free的拦截器部分调用方法,而/ api / members的拦截器根本没有引起作用?
答案 0 :(得分:1)
我看到那里发生了很多事情,如果不经过测试,很难确定。
但是我发现了与您提到的匿名TypeToken
相关的几件事。
我认为可以将其提取为常量,如下所示:
@Log4j2
@RestController
@RequestMapping("/api/videos")
public class VideoController {
private static final TypeToken<List<com.helan.videoafisha.dto.backend.frontend.admin.videos.free.FreeVideo>> FREE_VIDEO_TYPE = new TypeToken<>(){}.getType();
@PreAuthorize("hasAnyRole('DEVICE', 'ADMIN')")
@Transactional
@RequestMapping(value = "/free", method = RequestMethod.GET)
public List<com.helan.videoafisha.dto.backend.frontend.admin.videos.free.FreeVideo> freeVideos() {
return modelMapper.map(FREE_VIDEO_TYPE, freeVideoRepository.findAllWithVideo());
}
}
通过这样做,您还避免了在每次调用中仅为了获取其类型而创建一个新对象。
另一件事是,看起来像添加令牌,并且映射中的查询值被反转,因此在我的示例中,我将映射添加为键,然后添加了查询的值。
我也看不到modelMapper
对象来自任何地方。除非那是一个类并且其map
方法是静态的,否则您的示例将丢失一些代码。 freeVideoRepository
和memberRepository
都是相同的。
此外,请先尝试在不进行身份验证的情况下进行测试,以查看其是否有效,以便您缩小问题范围。
我希望它会有所帮助。