Spring Boot REST Api JWT AuthorizationFilter不验证令牌

时间:2018-08-11 15:54:49

标签: java spring spring-boot jwt

我制作了一个示例春天启动应用程序,该应用程序实现了部分起作用的JWT令牌身份验证。这意味着,直到通过使用/ login url发送用户详细信息来生成令牌,它才允许请求访问端点。收到令牌后,将使用称为授权的标头发送令牌。因此,直到第一个url都带有此标头,才允许访问端点。但是在第一个调用之后,我可以访问没有Encryption头(包含JWT令牌)的点。

SecurityConfig.java

@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    private final CustomUserDetailsService customUserDetailsService;

    @Autowired
    public SecurityConfig(CustomUserDetailsService customUserDetailsService) {
    this.customUserDetailsService = customUserDetailsService;
    System.out.println("from SecurityConfig constructor");
    System.out.println(this.customUserDetailsService.loadUserByUsername("batman").getUsername());
    }


    @Override
    protected void configure(HttpSecurity http) throws Exception {
    System.out.println("from configure");
    http.cors().and().csrf().disable().authorizeRequests()

    .antMatchers(HttpMethod.POST, "/sign_up").permitAll()
    .antMatchers("/*/floor1/**").hasRole("USER")
    .antMatchers("/*/floor2/**").hasRole("ADMIN")
    .and()
    .addFilter(new JwtAuthenticationFilter(authenticationManager()))
    .addFilter(new JwtAuthorizationFilter(authenticationManager(), customUserDetailsService));
    }


}

JwtAuthenticationFilter.java

public class JwtAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
    private AuthenticationManager authenticationManager;

    public JwtAuthenticationFilter(AuthenticationManager authenticationManager) {
    this.authenticationManager = authenticationManager;
    }

    @Override
    // {"username":"batman","password":"123"}
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
    try {
        System.out.println(">>>>> AuthenticationFilter: checking user credentials....");
        ApplicationUser applicationUser = new ObjectMapper().readValue(request.getInputStream(), ApplicationUser.class);
        return authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(applicationUser.getUsername(), applicationUser.getPassword()));
    } catch (IOException e) {
        System.out.println(">>>>> AuthenticationFilter: error in checking user credentials....");
        throw new RuntimeException(e);
    } catch (Exception e) {
        System.out.println(">>>>> AuthenticationFilter: error in checking user credentials....");
        throw new RuntimeException(e);
    }
    }

    @Override
    protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {
    System.out.println(">>>>> AuthenticationFilter: successfulAuthentication creating token...");
    ZonedDateTime expirationTimeUTC = ZonedDateTime.now(ZoneOffset.UTC).plus(SecurityConstants.EXPIRATION_TIME, ChronoUnit.MILLIS);
    String token = Jwts.builder().setSubject(((User)authResult.getPrincipal()).getUsername())
        .setExpiration(Date.from(expirationTimeUTC.toInstant()))
        .signWith(SignatureAlgorithm.HS256, SecurityConstants.SECRET)
        .compact();
    response.getWriter().write(token);
    response.addHeader(SecurityConstants.HEADER_STRING, SecurityConstants.TOKEN_PREFIX + token);
    System.out.println(">>>>> AuthenticationFilter: successfulAuthentication token created and added to response");
    }

}

JwtAuthorizationFilter.java

public class JwtAuthorizationFilter extends BasicAuthenticationFilter {
    private final CustomUserDetailsService customUserDetailsService;


    public JwtAuthorizationFilter(AuthenticationManager authenticationManager, CustomUserDetailsService customUserDetailsService) {
    super(authenticationManager);
    this.customUserDetailsService = customUserDetailsService;
    }


    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
    String header = request.getHeader(SecurityConstants.HEADER_STRING);
    System.out.println(">>>>> AuthorizationFilter doFilterInternal: checking the availability of toke header...");
    if(header == null || !header.startsWith(SecurityConstants.TOKEN_PREFIX)){
        System.out.println(">>>>> AuthorizationFilter doFilterInternal: header is null or not start with token prefix");
        chain.doFilter(request, response);
        return;
    }
    UsernamePasswordAuthenticationToken authenticationToken = getAuthenticationToken(request);
    SecurityContextHolder.getContext().setAuthentication(authenticationToken);
    chain.doFilter(request, response);
    }

    private UsernamePasswordAuthenticationToken getAuthenticationToken(HttpServletRequest request){
    System.out.println(">>>>> AuthorizationFilter UsernamePasswordAuthentication: validating the token...");
    String token = request.getHeader(SecurityConstants.HEADER_STRING);
    if(token == null){
        System.out.println(">>>>> AuthorizationFilter UsernamePasswordAuthentication: error: token is null");
        return null;
    }
    String username = Jwts.parser().setSigningKey(SecurityConstants.SECRET).parseClaimsJws(token.replace(SecurityConstants.TOKEN_PREFIX, "")).getBody().getSubject();
    UserDetails userDetails = customUserDetailsService.loadUserByUsername(username);
    ApplicationUser applicationUser = customUserDetailsService.loadApplicationUserByUsername(username);
    return username != null ? new UsernamePasswordAuthenticationToken(applicationUser, null, userDetails.getAuthorities()) : null;
    }


}

在JwtAuthorizationFilter.java中,在检查令牌是否为null的地方返回true。所以应该防止访问端点 并给客户一个错误。但事实并非如此。它允许请求通过过滤器 并访问端点。如果我在这里缺少任何东西,请帮助我。

完成示例项目:https://github.com/xandar6/jwt

0 个答案:

没有答案