前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Spring Boot的安全配置(三)

Spring Boot的安全配置(三)

原创
作者头像
堕落飞鸟
发布2023-04-05 15:41:04
1.2K0
发布2023-04-05 15:41:04
举报
文章被收录于专栏:飞鸟的专栏

JWT

JWT(JSON Web Token)是一种用于在网络中传输安全信息的开放标准(RFC 7519)。它可以在各个服务之间安全地传递用户认证信息,因为它使用数字签名来验证信息的真实性和完整性。

JWT有三个部分,每个部分用点(.)分隔:

  • Header:通常包含JWT使用的签名算法和令牌类型。
  • Payload:包含有关用户或其他主题的声明信息。声明是有关实体(通常是用户)和其他数据的JSON对象。声明被编码为JSON,然后使用Base64 URL编码。
  • Signature:用于验证消息是否未被篡改并且来自预期的发送者。签名由使用Header中指定的算法和秘钥对Header和Payload进行加密产生。

在Spring Boot中,您可以使用Spring Security和jjwt库来实现JWT的认证和授权。下面是一个使用JWT的示例:

代码语言:javascript
复制
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Value("${jwt.secret}")
    private String jwtSecret;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()
            .authorizeRequests()
            .antMatchers(HttpMethod.POST, "/api/authenticate").permitAll()
            .anyRequest().authenticated()
            .and()
            .addFilter(new JwtAuthenticationFilter(authenticationManager(), jwtSecret))
            .addFilter(new JwtAuthorizationFilter(authenticationManager(), jwtSecret))
            .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
    }

    @Override
    public void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(new JwtAuthenticationProvider(jwtSecret));
    }
}

在上面的示例中,SecurityConfig类继承了WebSecurityConfigurerAdapter并使用了@EnableWebSecurity注解启用Spring Security。configure()方法使用HttpSecurity对象来配置HTTP请求的安全性。.csrf().disable()禁用了CSRF保护。.authorizeRequests()表示进行授权请求。.antMatchers(HttpMethod.POST, "/api/authenticate").permitAll()表示允许POST请求到/api/authenticate路径。.anyRequest().authenticated()表示要求所有其他请求都需要身份验证。.addFilter(new JwtAuthenticationFilter(authenticationManager(), jwtSecret)).addFilter(new JwtAuthorizationFilter(authenticationManager(), jwtSecret))分别添加JWT认证和授权过滤器。.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)指定了会话管理策略。

configure()方法中还有一个configure(AuthenticationManagerBuilder auth)方法,它使用JwtAuthenticationProvider类配置身份验证。在这里,jwtSecret被注入到JwtAuthenticationProvider构造函数中,以便在认证过程中使用。

下面是JwtAuthenticationFilterJwtAuthorizationFilter的实现:

代码语言:javascript
复制
public class JwtAuthenticationFilter extends UsernamePasswordAuthenticationFilter {

    private final AuthenticationManager authenticationManager;
    private final String jwtSecret;

    public JwtAuthenticationFilter(AuthenticationManager authenticationManager, String jwtSecret) {
        this.authenticationManager = authenticationManager;
        this.jwtSecret = jwtSecret;
        setFilterProcessesUrl("/api/authenticate");
    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) {
        try {
            LoginRequest loginRequest = new ObjectMapper().readValue(request.getInputStream(), LoginRequest.class);
            Authentication authentication = new UsernamePasswordAuthenticationToken(
                    loginRequest.getUsername(),
                    loginRequest.getPassword()
            );
            return authenticationManager.authenticate(authentication);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) {
        UserPrincipal userPrincipal = (UserPrincipal) authResult.getPrincipal();
        String token = Jwts.builder()
                .setSubject(userPrincipal.getUsername())
                .setIssuedAt(new Date())
                .setExpiration(new Date(System.currentTimeMillis() + 864000000))
                .signWith(SignatureAlgorithm.HS512, jwtSecret)
                .compact();
        response.addHeader("Authorization", "Bearer " + token);
    }
}

JwtAuthenticationFilter类继承了UsernamePasswordAuthenticationFilter类,它用于处理基于用户名和密码的身份验证。它还使用AuthenticationManager来验证用户名和密码是否正确。jwtSecret在构造函数中被注入,用于生成JWT令牌。

attemptAuthentication()方法中,LoginRequest对象被反序列化为从请求中获取的用户名和密码。这些值被封装到UsernamePasswordAuthenticationToken中,并传递给AuthenticationManager以验证用户身份。

在身份验证成功后,successfulAuthentication()方法被调用。在这里,UserPrincipal对象被从Authentication对象中获取,然后使用Jwts类生成JWT令牌。setSubject()方法将用户名设置为JWT主题。setIssuedAt()方法设置JWT令牌的发行时间。setExpiration()方法设置JWT令牌的到期时间。signWith()方法使用HS512算法和jwtSecret密钥对JWT令牌进行签名。最后,JWT令牌被添加到响应标头中。

下面是JwtAuthorizationFilter的实现:

代码语言:javascript
复制
public class JwtAuthorizationFilter extends BasicAuthenticationFilter {

    private final String jwtSecret;

    public JwtAuthorizationFilter(AuthenticationManager authenticationManager, String jwtSecret) {
        super(authenticationManager);
        this.jwtSecret = jwtSecret;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
        String authorizationHeader = request.getHeader("Authorization");
        if (authorizationHeader == null || !authorizationHeader.startsWith("Bearer ")) {
            chain.doFilter(request, response);
            return;
        }
        String token = authorizationHeader.replace("Bearer ", "");
        try {
            Jws<Claims> claimsJws = Jwts.parser().setSigningKey(jwtSecret).parseClaimsJws(token);
            String username = claimsJws.getBody().getSubject();
            List<String> authorities = (List<String>) claimsJws.getBody().get("authorities");
            List<GrantedAuthority> grantedAuthorities = authorities.stream()
                    .map(SimpleGrantedAuthority::new)
                    .collect(Collectors.toList());
            Authentication authentication = new UsernamePasswordAuthenticationToken(username, null, grantedAuthorities);
            SecurityContextHolder.getContext().setAuthentication(authentication);
            chain.doFilter(request, response);
        } catch (JwtException e) {
            response.setStatus(HttpStatus.UNAUTHORIZED.value());
        }
    }
}

JwtAuthorizationFilter类继承了BasicAuthenticationFilter类,并覆盖了doFilterInternal()方法。在这个方法中,请求头中的Authorization标头被解析,如果它不是以Bearer开头,则直接传递给过滤器链。否则,从令牌中解析出主题(用户名)和授权信息,然后创建一个包含用户身份验证和授权信息的Authentication对象,并将其设置到SecurityContextHolder中。

如果JWT令牌无效,JwtException将被抛出,并返回HTTP 401未经授权的错误。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • JWT
相关产品与服务
多因子身份认证
多因子身份认证(Multi-factor Authentication Service,MFAS)的目的是建立一个多层次的防御体系,通过结合两种或三种认证因子(基于记忆的/基于持有物的/基于生物特征的认证因子)验证访问者的身份,使系统或资源更加安全。攻击者即使破解单一因子(如口令、人脸),应用的安全依然可以得到保障。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档