SringSecurity认证——SpringSecurity集成JWT保姆级教程

SringSecurity认证——SpringSecurity集成JWT保姆级教程Spring Security 是一个功能强大且高度可定制的安全框架 用于保护基于 Spring 的应用程序 它提供了多种认证方式 以满足不同场景下的安全需求

欢迎大家来到IT世界,在知识的湖畔探索吧!

Spring Security是一个功能强大且高度可定制的安全框架,用于保护基于Spring的应用程序。它提供了多种认证方式,以满足不同场景下的安全需求。以下是对Spring Security主要认证方式的概述:

  1. 表单登录(Form Login):这是最常见的认证方式,用户通过浏览器访问受保护的资源时,会被重定向到一个登录页面。用户在登录页面输入用户名和密码,然后提交表单。Spring Security拦截表单提交请求,验证用户名和密码,成功后创建安全上下文,允许用户访问受保护的资源。
  2. HTTP基本认证(HTTP Basic Authentication):一种简单的认证机制,客户端在请求头中包含用户名和密码(Base64编码)。通常用于测试或API认证,不适用于交互式Web应用,因为用户名和密码会在每次请求中暴露。
  3. HTTP摘要认证(HTTP Digest Authentication):对HTTP基本认证的一种改进,使用MD5摘要算法对用户名、密码和请求细节进行加密。提供了比基本认证更高的安全性,但仍需要客户端存储密码。
  4. 记住我(Remember Me):允许用户在登录时选择“记住我”选项,以便在后续访问时无需重新输入用户名和密码。通常通过设置一个持久的cookie来实现,该cookie包含用户的唯一标识符,而不是密码。
  5. OAuth2/OpenID Connect:OAuth2是一个用于授权的行业标准协议,允许用户授权第三方应用访问他们在其他服务上的信息,而无需将用户名和密码提供给第三方。OpenID Connect是OAuth2的扩展,用于身份验证,提供了标准的方式来验证用户的身份并获取关于用户的信息。
  6. CAS(Central Authentication Service):一种企业级的单点登录解决方案,允许用户在一个地方登录,然后访问多个应用而无需重新登录。CAS服务器负责处理认证请求,并将认证结果返回给客户端应用。
  7. JWT(JSON Web Tokens):一种用于双方之间安全传输信息的简洁的、URL安全的令牌标准。JWT通常用于身份验证和信息交换,因为它们可以在客户端和服务器之间安全地传输用户信息。
  8. LDAP(Lightweight Directory Access Protocol):一种用于访问和维护分布式目录信息服务的协议。LDAP常用于存储用户和密码信息,Spring Security提供了对LDAP认证的支持。
  9. 自定义认证:Spring Security允许开发者实现自定义的认证逻辑,以满足特定的安全需求。这通常涉及实现AuthenticationProvider接口,并在Spring Security配置中注册该提供程序。

这些认证方式可以单独使用,也可以组合使用,以构建满足特定安全需求的多因素认证系统。在选择认证方式时,应考虑应用的安全性需求、用户体验以及现有基础架构的兼容性,其中JWT(JSON Web Tokens)是使用较多的一种,今天就SpringSecurity集成JWT展开完整概述如下:

JWT (JSON Web Token) 简述

JWT 是一种开放标准 (RFC 7519),用于在网络应用环境间安全地传输信息。它是一种紧凑且自包含的方式,用于在各方之间传递声明(claims),这些声明通常是为了验证用户的身份,也可以被用来交换其他类型的信息。

一个典型的JWT由三部分组成,它们通过点号(.)分隔:

  1. 头部 (Header):包含了令牌的元数据,如使用的签名算法。
  2. 载荷 (Payload):包含了声明,即要传达的数据。这些声明可以是预定义的(如iss、exp等)或自定义的。
  3. 签名 (Signature):用于验证消息在传输过程中没有被更改,并且,对于私有密钥签名的令牌来说,还可以确认发送方的身份。
  4. 示例
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

欢迎大家来到IT世界,在知识的湖畔探索吧!

Spring Security 集成 JWT 的作用和意义

  1. 无状态认证:JWT使得认证过程无状态化,服务器端不需要存储会话信息,这有助于提高系统的可扩展性,特别是对于微服务架构或分布式系统。
  2. 跨域资源共享 (CORS):客户端可以在每次请求时携带JWT作为身份验证信息,无需依赖于服务器端的Session,这对单页应用(SPA)或者前后端分离的应用尤为重要。
  3. 简化移动端开发:移动端应用可以通过存储JWT来保持用户的登录状态,简化了移动端的安全实现。
  4. 增强安全性:JWT可以包含签名以确保内容未被篡改,并可以设置过期时间来限制其有效期限。
  5. 自包含:JWT令牌中包含了所有必要的用户信息,减少了对数据库查询的需求,提升了性能。
  6. 易于传播:JWT可以通过HTTP头部轻松传播,方便API间的通信。
  7. 支持多种平台:几乎所有的编程语言都有相应的库来处理JWT,促进了不同技术栈之间的互操作性。
  8. 细粒度访问控制:可以在JWT中编码权限信息,允许更精细的访问控制决策。
  9. 提高用户体验:通过记住我功能或刷新令牌机制,可以让用户长时间保持登录状态。

Spring Security 集成 JWT 的主要步骤

  1. 添加必要的依赖:确保项目中包含Spring Security和JWT相关的库。
  2. 配置安全设置:创建或修改SecurityConfig类,禁用Session管理并启用无状态认证。
  3. 实现JWT工具类:创建一个工具类来处理JWT的生成、解析和验证。
  4. 创建JWT过滤器:实现一个自定义的JwtTokenFilter来拦截请求并解析JWT。
  5. 配置用户详情服务:实现UserDetailsService接口来加载用户特定的数据。
  6. 创建认证管理器:配置AuthenticationManager以支持用户名密码认证。
  7. 登录控制器:创建一个控制器来处理登录请求,并返回JWT给客户端。
  8. 保护API端点:使用Spring Security配置来保护需要认证的API端点。

完整代码示例

1. 添加依赖 (Maven)

欢迎大家来到IT世界,在知识的湖畔探索吧! 
   
    
    
      org.springframework.boot 
     
    
      spring-boot-starter-security 
     
    
    
    
      io.jsonwebtoken 
     
    
      jjwt 
     
    
      {版本号根据自己的spring框架版本进行选择} 
     
    
  

2. 自定义SecurityConfig

@Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private JwtTokenProvider jwtTokenProvider; @Override protected void configure(HttpSecurity http) throws Exception { http .csrf().disable() // 禁用CSRF防护,对于REST API来说通常不需要 .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) // 禁用Session .and() .authorizeRequests() .antMatchers("/auth/login").permitAll() // 登录路径无需认证 .anyRequest().authenticated() // 其他所有请求都需要认证 .and() .apply(new JwtConfigurer(jwtTokenProvider)); // /关键代码/应用JWT配置 } @Bean @Override public AuthenticationManager authenticationManagerBean() throws Exception { return super.authenticationManagerBean(); } }

3. 添加JWT工具类 (JwtTokenProvider)

欢迎大家来到IT世界,在知识的湖畔探索吧!@Component public class JwtTokenProvider { private final String secret = "YourSecretKey"; // 秘钥用于签名JWT private final long validityInMilliseconds = ; // 令牌有效期(1小时) @Autowired private UserDetailsService userDetailsService; public String createToken(String username, List 
  
    roles) { Claims claims = Jwts.claims().setSubject(username); claims.put("roles", roles); Date now = new Date(); Date validity = new Date(now.getTime() + validityInMilliseconds); return Jwts.builder() .setClaims(claims) .setIssuedAt(now) .setExpiration(validity) .signWith(SignatureAlgorithm.HS256, secret.getBytes()) .compact(); } public Authentication getAuthentication(String token) { UserDetails userDetails = this.userDetailsService.loadUserByUsername(getUsername(token)); return new UsernamePasswordAuthenticationToken(userDetails, "", userDetails.getAuthorities()); } public String getUsername(String token) { return Jwts.parser() .setSigningKey(secret.getBytes()) .parseClaimsJws(token) .getBody() .getSubject(); } public boolean validateToken(String token) { try { Jws 
   
     claims = Jwts.parser() .setSigningKey(secret.getBytes()) .parseClaimsJws(token); if (claims.getBody().getExpiration().before(new Date())) { return false; } return true; } catch (JwtException | IllegalArgumentException e) { throw new InvalidJwtAuthenticationException("Expired or invalid JWT token"); } } } 
    
  

4. 添加JWT过滤器 (JwtTokenFilter)

public class JwtTokenFilter extends OncePerRequestFilter { private final JwtTokenProvider jwtTokenProvider; public JwtTokenFilter(JwtTokenProvider jwtTokenProvider) { this.jwtTokenProvider = jwtTokenProvider; } @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { String token = resolveToken(request); try { if (token != null && jwtTokenProvider.validateToken(token)) { Authentication auth = jwtTokenProvider.getAuthentication(token); SecurityContextHolder.getContext().setAuthentication(auth); } } catch (InvalidJwtAuthenticationException ex) { // Handle expired or invalid JWT token } filterChain.doFilter(request, response); } private String resolveToken(HttpServletRequest request) { String bearerToken = request.getHeader("Authorization"); if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) { return bearerToken.substring(7); } return null; } }

5. 配置JWT (JwtConfigurer)

欢迎大家来到IT世界,在知识的湖畔探索吧!public class JwtConfigurer extends SecurityConfigurerAdapter 
  
    { private final JwtTokenProvider jwtTokenProvider; public JwtConfigurer(JwtTokenProvider jwtTokenProvider) { this.jwtTokenProvider = jwtTokenProvider; } @Override public void configure(HttpSecurity http) throws Exception { JwtTokenFilter customFilter = new JwtTokenFilter(jwtTokenProvider); http.addFilterBefore(customFilter, UsernamePasswordAuthenticationFilter.class); } } 
  

6. 添加用户详情服务接口自定义实现类 (CustomUserDetailsService)

@Service public class CustomUserDetailsService implements UserDetailsService { @Autowired private UserRepository userRepository; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { //自己根据实际情况实现查询数据库获取用户信息,并构建用户信息 User user = userRepository.findByUsername(username) .orElseThrow(() -> new UsernameNotFoundException("User not found")); return org.springframework.security.core.userdetails.User.builder() .username(user.getUsername()) .password(user.getPassword()) .authorities(user.getRoles().toArray(new SimpleGrantedAuthority[0])) .build(); } }

7. 创建认证管理器 (AuthConfiguration)

欢迎大家来到IT世界,在知识的湖畔探索吧!@Configuration public class AuthConfiguration { @Autowired private DataSource dataSource; @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } @Bean public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception { return authenticationConfiguration.getAuthenticationManager(); } }

8. 登录控制器 (AuthController)

@RestController @RequestMapping("/auth") public class AuthController { @Autowired private AuthenticationManager authenticationManager; @Autowired private JwtTokenProvider jwtTokenProvider; @PostMapping("/login") public ResponseEntity 
   authenticate(@RequestBody LoginRequest loginRequest) { try { Authentication authentication = authenticationManager.authenticate( new UsernamePasswordAuthenticationToken( loginRequest.getUsername(), loginRequest.getPassword() ) ); SecurityContextHolder.getContext().setAuthentication(authentication); String jwt = jwtTokenProvider.createToken(authentication.getName(), getRolesFromAuthentication(authentication)); return ResponseEntity.ok(new JwtResponse(jwt)); } catch (AuthenticationException e) { throw new BadCredentialsException("Invalid username/password supplied"); } } private List 
  
    getRolesFromAuthentication(Authentication authentication) { return authentication.getAuthorities().stream() .map(GrantedAuthority::getAuthority) .collect(Collectors.toList()); } } // DTOs for requests and responses class LoginRequest { private String username; private String password; // getters and setters } class JwtResponse { private String jwt; // constructor, getters and setters } 
  

以上代码提供了一个完整的框架,用于将JWT集成到Spring Security中。请注意,在实际应用中,你可能需要根据具体需求调整代码,比如使用更复杂的密钥管理、刷新令牌机制、更好的异常处理等。此外,确保遵循最佳实践来保护你的应用程序,如HTTPS协议的使用。

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://itzsg.com/116503.html

(0)
上一篇 1天前
下一篇 1天前

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

联系我们YX

mu99908888

在线咨询: 微信交谈

邮件:itzsgw@126.com

工作时间:时刻准备着!

关注微信