Spring JWT 过滤器配置

Posted

技术标签:

【中文标题】Spring JWT 过滤器配置【英文标题】:Spring JWT Filter Configuration 【发布时间】:2016-07-13 04:32:22 【问题描述】:

我想添加一个过滤器来使用令牌对用户进行身份验证。我通过添加两个过滤器来实现这一点:

public class JwtFilter extends GenericFilterBean 

private TokenAuthenticationService authenticationService;

public JwtFilter(TokenAuthenticationService service) 
    this.authenticationService = service;


public JwtFilter() 


@Override
public void doFilter(final ServletRequest request,
                     final ServletResponse response,
                     final FilterChain chain) throws IOException, ServletException 
    System.out.println("JwtFilter.doFilter");
    SecurityContextHolder.getContext().setAuthentication(
            authenticationService.getAuthentication((HttpServletRequest) request));
    chain.doFilter(request, response);

之后我创建了第二个过滤器,以授权用户:

public class StatelessLoginFilter extends AbstractAuthenticationProcessingFilter 


private final TokenAuthenticationService tokenAuthenticationService;
private final UserDetailsService userService;

public StatelessLoginFilter(String urlMapping, TokenAuthenticationService tokenAuthenticationService,
                            UserDetailsService userDetailsService, AuthenticationManager authManager) 
    super(new AntPathRequestMatcher(urlMapping));
    this.userService = userDetailsService;
    this.tokenAuthenticationService = tokenAuthenticationService;
    setAuthenticationManager(authManager);


@Override
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException 
    System.out.println("StatelessLoginFilter.successfulAuthentication");
    // Lookup the complete User object from the database and create an Authentication for it
    final User authenticatedUser = (User) userService.loadUserByUsername(authResult.getName());
    final UserAuthentication userAuthentication = new UserAuthentication(authenticatedUser);

    // Add the custom token as HTTP header to the response
    tokenAuthenticationService.addAuthentication(response, userAuthentication);

    // Add the authentication to the Security context
    SecurityContextHolder.getContext().setAuthentication(userAuthentication);


@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException 
    System.out.println("StatelessLoginFilter.attemptAuthentication");
    final User user = new ObjectMapper().readValue(request.getInputStream(), User.class);
    final UsernamePasswordAuthenticationToken loginToken = new U

sernamePasswordAuthenticationToken(
                user.getUsername(), user.getPassword());
        return getAuthenticationManager().authenticate(loginToken);
   

这是我的安全配置:

    @Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter 

    @Autowired
    private UserDetailsService userDetailsService;

    @Autowired
    private TokenAuthenticationService tokenAuthenticationService;



    @Override
    protected void configure(HttpSecurity http) throws Exception 
        http    .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()

                .authorizeRequests()
                .antMatchers("/user/**").authenticated()
                .anyRequest().permitAll().and()
                .addFilterBefore(new StatelessLoginFilter("/login", tokenAuthenticationService, userDetailsService, authenticationManager()), UsernamePasswordAuthenticationFilter.class)
                .addFilterBefore(new JwtFilter(tokenAuthenticationService), UsernamePasswordAuthenticationFilter.class);
    

    @Bean
    public AuthenticationManager authenticationManagerBean() throws Exception
        return super.authenticationManagerBean();
    

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception 
     auth .inMemoryAuthentication()
                .withUser("user").password("password").roles("USER");
    

    @Override
    protected UserDetailsService userDetailsService() 
        return userDetailsService;
    


现在,当我向“/login”发送请求时,我得到 404 错误页面。真的,我没有映射控制器,但在安全方面,安全配置中有一个 url 映射。正如我在文档中所读到的:

创建一个具有特定模式的匹配器,它将以不区分大小写的方式匹配所有 HTTP 方法。

另外,你可以看到 System.out.println() 行。我在这里设置了断点,但是执行没有到达这行。我不确定我是否正确注册了此过滤器。我的代码主要基于这个存储库:https://github.com/BranislavLazic/angular-security

【问题讨论】:

【参考方案1】:

Springboot JWT Starter 是使用 JWT 启动无状态 springboot 应用程序的好方法。

如下所示编写您的 SecurityConfiguration。

protected void configure(HttpSecurity http) throws Exception 
    http
            .csrf()
            .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()).and()
            .sessionManagement().sessionCreationPolicy( SessionCreationPolicy.STATELESS ).and()
            .exceptionHandling().authenticationEntryPoint( restAuthenticationEntryPoint ).and()
            .addFilterBefore(jwtAuthenticationTokenFilter(), BasicAuthenticationFilter.class)
            .authorizeRequests()
                .antMatchers("/", "/index.html", "/login.html", "/home.html").permitAll()
              .anyRequest()
                .authenticated().and()
            .formLogin()
                .successHandler(authenticationSuccessHandler)
                .failureHandler(authenticationFailureHandler).and()
            .logout()
                .addLogoutHandler(jwtLogoutHandler())
                .logoutSuccessHandler((new HttpStatusReturningLogoutSuccessHandler(HttpStatus.OK))) ;

过滤器

@Override
public void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException 

    String authToken = getToken( request );
    // get username from token
    String username = tokenHelper.getUsernameFromToken( authToken );
    if ( username != null ) 
        // get user
        UserDetails userDetails = userDetailsService.loadUserByUsername( username );
        // create authentication
        TokenBasedAuthentication authentication = new TokenBasedAuthentication( userDetails );

        authentication.setToken( authToken );
        authentication.setAuthenticated( true );
        SecurityContextHolder.getContext().setAuthentication(authentication);
    

    chain.doFilter(request, response);

有关更多信息,请查看源代码: https://github.com/bfwg/springboot-jwt-starter/blob/master/src/main/java/com/bfwg/security/auth/TokenAuthenticationFilter.java

【讨论】:

以上是关于Spring JWT 过滤器配置的主要内容,如果未能解决你的问题,请参考以下文章

前后端分离的Web应用程序中使用Spring Security+Mybatis+JWT非对称加密+动态权限管理:身份验证过滤器

Spring Boot 配置问题中的 JWT 令牌

JWT spring security Authentication过滤器丢失标头信息

在 Spring Boot 2 上实现基于过滤器的 JWT 身份验证与 OAuth2 JWT 身份验证

Spring过滤器将角色添加到来自令牌的请求

spring-security-jwt的总结与实现