带有 spring-boot 和 spring-security 的 JWT

Posted

技术标签:

【中文标题】带有 spring-boot 和 spring-security 的 JWT【英文标题】:JWT with spring-boot and spring-security 【发布时间】:2018-01-29 22:33:36 【问题描述】:

我对 Spring-Security 非常陌生。我正在尝试在我的spring-boot 应用程序中实现JWT 以执行authentication。我跟着示例代码,我能够生成jwt。但是根据示例文件中的配置,我可以使用配置中的内存数据集验证HttpRequest 中的输入。但是,我不明白如何检查request 中发送的usernamepassword 以及我的database 中存在的值。请指导我。我的配置类是

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter 

@Override
protected void configure(HttpSecurity http) throws Exception 
    http.csrf().disable().authorizeRequests()
            .antMatchers("/").permitAll()
            .antMatchers(HttpMethod.POST, "/login").permitAll()
            .anyRequest().authenticated()
            .and()
            // We filter the api/login requests
            .addFilterBefore(new JWTLoginFilter("/login", authenticationManager()),
                    UsernamePasswordAuthenticationFilter.class)
            // And filter other requests to check the presence of JWT in header
            .addFilterBefore(new JWTAuthenticationFilter(),
                    UsernamePasswordAuthenticationFilter.class);


@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception 
    // Create a default account
    auth.inMemoryAuthentication()
            .withUser("admin")
            .password("password")
            .roles("ADMIN");


在被覆盖的configure(AuthenticationManagerBuilder auth) throws Exception 中,我可以设置凭据,该凭据将与request 中存在的凭据进行比较/login 路径

public class TokenAuthenticationService 

static final long EXPIRATIONTIME = 864_000_000; // 10 days
static final String SECRET = "ThisIsASecret";
static final String TOKEN_PREFIX = "Bearer";
static final String HEADER_STRING = "Authorization";

static void addAuthentication(HttpServletResponse res, String username)     
    String JWT = Jwts.builder()
            .setSubject(username)
            .setExpiration(new Date(System.currentTimeMillis() + EXPIRATIONTIME))
            .signWith(SignatureAlgorithm.HS512, SECRET)
            .compact();
    res.addHeader(HEADER_STRING, TOKEN_PREFIX + " " + JWT);


static Authentication getAuthentication(HttpServletRequest request) 
    String token = request.getHeader(HEADER_STRING);
    if (token != null) 
        // parse the token.
        String user = Jwts.parser()
                .setSigningKey(SECRET)
                .parseClaimsJws(token.replace(TOKEN_PREFIX, ""))
                .getBody()
                .getSubject();

        return user != null ?
                new UsernamePasswordAuthenticationToken(user, null, Collections.emptyList()) :
                null;
    
    return null;



public class JWTLoginFilter extends AbstractAuthenticationProcessingFilter 

public JWTLoginFilter(String url, AuthenticationManager authManager) 
super(new AntPathRequestMatcher(url));
setAuthenticationManager(authManager);


@Override
public Authentication attemptAuthentication(
        HttpServletRequest req, HttpServletResponse res)
        throws AuthenticationException, IOException, ServletException 
    AccountCredentials creds = new ObjectMapper()
            .readValue(req.getInputStream(), AccountCredentials.class);
    return getAuthenticationManager().authenticate(
            new UsernamePasswordAuthenticationToken(
                    creds.getUsername(),
                    creds.getPassword(),
                    Collections.emptyList()
            )
    );


@Override
protected void successfulAuthentication(
        HttpServletRequest req,
        HttpServletResponse res, FilterChain chain,
        Authentication auth) throws IOException, ServletException 
    TokenAuthenticationService
            .addAuthentication(res, auth.getName());



public class JWTAuthenticationFilter extends GenericFilterBean

@Override
public void doFilter(ServletRequest request,
                     ServletResponse response,
                     FilterChain filterChain)
        throws IOException, ServletException 
    Authentication authentication = TokenAuthenticationService
            .getAuthentication((HttpServletRequest)request);

    SecurityContextHolder.getContext()
            .setAuthentication(authentication);
    filterChain.doFilter(request,response);


【问题讨论】:

【参考方案1】:

您需要实现 UserDetailsS​​ervice 接口(访问您的数据库)并配置它以供 Spring Security 使用。

一个很好的例子(没有 JWT,但这不是重点)可以在这里找到:Spring Security: Authentication with a Database-backed UserDetailsService

【讨论】:

以上是关于带有 spring-boot 和 spring-security 的 JWT的主要内容,如果未能解决你的问题,请参考以下文章

带有 spring-boot 和 spring-security 的 JWT

带有spring-boot安全休息api的角度2

带有 pom.xml 和 app.java 的简单 spring-boot 应用程序显示构建失败错误

如何使用带有 gradle 的多个嵌入式服务器运行 spring-boot 集成测试

在带有 spring-boot rest 和 Swagger 的标头中使用 utf-8 字符时未加载响应

带有spring-boot的自定义sql中的Liquibase参数