Spring Security 超详细整合 JWT,能否拿下看你自己!

Spring Security是一个功能强大并且高度可定制的Java安全框架,用于保护基于Spring的应用程序。JWT(JSON Web Tokens)是一种用于在网络应用环境间传递声明的一种紧凑的、URL安全的方式。JWT可以被用来认证和信息交换。将Spring Security与JWT整合可以为应用程序提供一个安全且高效的认证机制。

以下是Spring Security与JWT整合的超详细步骤:

### 1. 环境准备
确保你的开发环境中已经包含了Spring Boot和Spring Security的依赖。

```xml
<!-- pom.xml中添加Spring Security和JWT的依赖 -->
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
    </dependency>
    <dependency>
        <groupId>io.jsonwebtoken</groupId>
        <artifactId>jjwt</artifactId>
        <version>你的JWT库版本</version>
    </dependency>
</dependencies>
```

### 2. 配置Spring Security
创建一个配置类来定义Spring Security的安全性策略。

```java
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint;

    @Autowired
    private JwtAccessDeniedHandler jwtAccessDeniedHandler;

    @Autowired
    private CustomTokenProvider tokenProvider;

    @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception {
        httpSecurity
            .csrf().disable()
            .authorizeRequests()
            .antMatchers("/api/public/**").permitAll()
            .anyRequest().authenticated()
            .and()
            .exceptionHandling()
            .authenticationEntryPoint(jwtAuthenticationEntryPoint)
            .accessDeniedHandler(jwtAccessDeniedHandler);
        httpSecurity
            .addFilterBefore(jwtRequestFilter(), FilterOrder.AUTHENTICATION);
    }

    @Bean
    public Filter jwtRequestFilter() {
        return new JwtRequestFilter(tokenProvider, authenticationManager());
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService()).passwordEncoder(passwordEncoder());
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    // 其他Bean定义...
}
```

### 3. JWT认证过滤器
创建JWT请求过滤器,用于拦截请求并验证JWT。

```java
public class JwtRequestFilter extends OncePerRequestFilter {

    private final CustomTokenProvider tokenProvider;
    private final AuthenticationManager authenticationManager;

    public JwtRequestFilter(CustomTokenProvider tokenProvider, AuthenticationManager authenticationManager) {
        this.tokenProvider = tokenProvider;
        this.authenticationManager = authenticationManager;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        String jwt = getJwtFromRequest(request);
        if (jwt != null && tokenProvider.validateToken(jwt)) {
            Authentication authentication = authenticationManager.authenticate(
                new JwtAuthenticationToken(jwt)
            );
            SecurityContextHolder.getContext().setAuthentication(authentication);
        }
        filterChain.doFilter(request, response);
    }

    private String getJwtFromRequest(HttpServletRequest request) {
        String bearerToken = request.getHeader("Authorization");
        if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) {
            return bearerToken.substring(7);
        }
        return null;
    }
}
```

### 4. JWT令牌提供者
创建一个服务来提供JWT令牌。

```java
@Service
public class CustomTokenProvider {

    public String generateToken(Authentication authentication) {
        UserDetails userDetails = (UserDetails) authentication.getPrincipal();
        // 构建JWT的payload
        String token = Jwts.builder()
                .setSubject(userDetails.getUsername())
                .setIssuedAt(new Date(System.currentTimeMillis()))
                .setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 60)) // 1小时后过期
                .signWith(SignatureAlgorithm.HS512, "your-secret-key").compact();
        return token;
    }

    public boolean validateToken(String token) {
        try {
            Jwts.parser().setSigningKey("your-secret-key").parseClaimsJws(token);
            return true;
        } catch (JwtException | IllegalArgumentException e) {
            return false;
        }
    }

    // 其他方法...
}
```

### 5. 用户详情服务
实现`UserDetailsService`接口,用于从数据库获取用户信息。

```java
@Service
public class CustomUserDetailsService implements UserDetailsService {

    @Autowired
    private UserRepository userRepository;
    @Autowired
    private PasswordEncoder passwordEncoder;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        User user = userRepository.findByUsername(username);
        if (user == null) {
            throw new UsernameNotFoundException("User not found with username: " + username);
        }
        return new org.springframework.security.core.userdetails.User(
                user.getUsername(),
                user.getPassword(),
                getAuthorities(user)
        );
    }

    private Collection<? extends GrantedAuthority> getAuthorities(User user) {
        List<SimpleGrantedAuthority> authorities = new ArrayList<>();
        // 根据用户角色添加权限...
        return authorities;
    }
}
```

### 6. 异常处理
创建自定义异常处理类,用于处理安全相关的异常。

```java
@Component
public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint {

    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException {
        response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized");
    }
}
```

### 7. 测试
编写单元测试和集成测试来验证安全性策略。

### 8. 部署
将应用程序部署到服务器或云环境。

整合Spring Security和JWT涉及到许多细节,上述步骤提供了一个大致的框架。在实际开发中,你可能需要根据具体需求调整配置和实现。
 

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值