I try to log all http requests by means of HandlerInterceptorAdapter:
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());
}
}
When I request /api/videos/free and / api/members (method get) by authorized user, everything works correctly:
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
If I make the same a requests by the anonymous, the log looks so:
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 and /api/members is very similar:
@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()
);
}
}
Code which is responsible for authentication:
@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);
}
}
Adding of the interceptor:
@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();
}
}
Why the interceptor for /api/videos/free calls methods partially, and for /api/members does not cause at all?
I see that there is a lot going on there and it is a bit hard to tell for sure without testing.
But I spotted a couple things related to the anonymous TypeToken that you have mentioned.
I think it could be extracted to a constant, like so:
@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());
}
}
By doing this you also avoid creating a new object in every call just to get its type.
Another thing is that it looks like adding the token and the queried values in the map is inverted, so in my example I added the map as a key and then the queried values.
Also I do not see the modelMapper object coming from anywhere. Unless that is a class and its map method is static, your example is missing some code. The same for freeVideoRepository and memberRepository.
Furthermore, try testing without authentication first to see if it works, so you can narrow down the issue.
I hope it helps.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With