Springboot学习记录(有关@Component和token)

一、关于@Component

首先我们要知道,什么是Bean呢?

Springboot ApplicationContext 是Springboot保存对象实例的地方,spring已确定将这些实例将被自动管理和分发。这些实例就叫做Bean。

@Component是一个注解,它允许spring自动检测和定义Bean。

即,无需编写任何明确的代码,Spring 就能做到:

  • 扫描应用,查找注解为 @Component 的类
  • 将它们实例化,并注入任何指定的依赖
  • 在需要的地方注入

Spring 提供了一些专门的元注解:@Controller@Service 和 @Repository。它们都提供了与 @Component 相同的功能。

它们的作用都是一样的,因为它们都是由 @Component 作为元注解组成的注解。它们就像 @Component 别名,在 Spring 自动检测或依赖注入之外有专门的用途和意义。

由于 @Component 和 @Bean 之间的差异,应该注意一些重要的影响。

  • @Component 是一个类级别的注解,而 @Bean 是方法级别的注解,因此只有在类的源代码可编辑时,才可以使用 @Component 作为选项。@Bean 始终可以使用,但它的语法更加冗长。
  • @Component 与 Spring 的自动检测兼容,但 @Bean 需要手动实例化类。
  • 使用 @Bean 可以将 Bean 的实例化与其类定义分离。因此,可以使用它将第三方类转化为 Spring Bean。这也意味着可以添加逻辑来决定要使用哪个实例作为 Bean。

内容来自: Spring 中的 @Component 注解 - spring 中文网 (springdoc.cn)

二、token

首先,token是什么意思呢?

在计算机术语中,它是“令牌”的意思。在计算机身份认证中,token通常指服务器端生成的一串字符串,用作客户端进行请求的一个令牌。用户首次登录后,服务器会生成一个token并将其返回给客户端。之后,客户端只需要使用这个token进行请求而无需再次提供用户名和密码,简化了身份验证过程。

其次,tokenPrefix又是什么意思呢?(一般是自定义)

tokenPrefix通常指的是用于生成token(令牌)时的一个统一前缀或者标识符。这个前缀用于标识token的类型、来源或用途,以便在后续的验证或处理过程中能够正确区分和识别不同的token。

主要作用有:

  1. 区分不同来源的token:在一个系统中,可能存在多种不同类型的token,比如用于用户身份验证的token、用于API调用的token等。通过为不同类型的token设置不同的前缀,可以很容易地区分它们。

  2. 增强安全性:通过在token中添加一个难以预测和伪造的前缀,可以增加token的复杂性和难以破解性,从而增强系统的安全性。

  3. 简化处理逻辑:在验证或处理token时,通过检查前缀可以快速确定token的类型和相应的处理逻辑,从而简化处理过程

举个例子:TOKEN的创建,验证和更新 。

创建TOKEN:

public static String createToken(String sub){
        return tokenPrefix + JWT.create()
                .withSubject(sub)
                .withExpiresAt(new Date(System.currentTimeMillis() + expireTime))
                .sign(Algorithm.HMAC512(secret));
    }
  1. 方法定义public static String createToken(String sub) 是一个公共静态方法,它接收一个字符串参数 sub 并返回一个字符串。这个字符串预期是一个JWT令牌。

  2. JWT类:代码中存在一个名为 JWT 的类,它有一个静态方法 create(),用于开始构建一个JWT。(这是我自己创建的类)

  3. 设置主题.withSubject(sub) 是 JWT 类的某个方法,用于设置JWT的主题(subject),即 sub 参数的值。在JWT中,主题通常用于标识令牌的接收者,比如用户的ID。

  4. 设置过期时间.withExpiresAt(new Date(System.currentTimeMillis() + expireTime)) 

  5. 签名JWT.sign(Algorithm.HMAC512(secret)) 

  6. 返回令牌

 验证TOKEN:

public static String validateToken(String token){
        try {
            return JWT.require(Algorithm.HMAC512(secret))
                    .build()
                    .verify(token.replace(tokenPrefix, ""))
                    .getSubject();
        } catch (TokenExpiredException e){
            throw new CustomException(401, "token已经过期");
        } catch (Exception e){
            throw new CustomException(401, "token验证失败");
        }
    }

更新TOKEN:

 public static boolean isNeedUpdate(String token){
        //获取token过期时间
        Date expiresAt = null;
        try {
            expiresAt = JWT.require(Algorithm.HMAC512(secret))
                    .build()
                    .verify(token.replace(tokenPrefix, ""))
                    .getExpiresAt();
        } catch (TokenExpiredException e){
            return true;
        } catch (Exception e){
            throw new CustomException(401, "token验证失败");
        }
        //如果剩余过期时间少于过期时常的一般时 需要更新
        return (expiresAt.getTime() - System.currentTimeMillis()) < (expireTime>>1);
    }

### Spring Boot Security JWT Token Integration Tutorial #### 1. 添加必要的依赖项 为了实现基于JWT的安全机制,在`pom.xml`文件中除了常规的Spring Boot Starter外,还需要加入安全模块以及JSON Web Tokens的支持。 ```xml <dependencies> <!-- Spring Boot Starter Security --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <!-- JSON Web Token Support --> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-api</artifactId> <version>0.11.2</version> </dependency> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-impl</artifactId> <version>0.11.2</version> <scope>runtime</scope> </dependency> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-jackson</artifactId> <!-- or jjwt-gson if Gson is preferred --> <version>0.11.2</version> <scope>runtime</scope> </dependency> </dependencies> ``` 上述配置引入了用于创建验证JWT令牌所需的库[^2]。 #### 2. 配置Security设置 通过自定义`WebSecurityConfigurerAdapter`类来调整默认的安全策略。这一步骤涉及定义哪些URL路径应该受到保护,并指定登录逻辑处理方式。 ```java @Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http.csrf().disable() .authorizeRequests() .antMatchers("/authenticate").permitAll() // Allow everyone to access the authentication endpoint. .anyRequest().authenticated(); // All other requests require authentication. // Add custom filter for processing tokens before reaching controllers. http.addFilterBefore(new JwtRequestFilter(), UsernamePasswordAuthenticationFilter.class); } } ``` 此部分代码禁用了CSRF防护并设置了基本的身份验证规则,允许未授权访问特定端点(如身份验证API),而其他请求则需经过身份验证才能继续执行[^3]。 #### 3. 创建Token服务 构建一个简单的接口用来生成新的JWT实例;通常情况下会包含用户的唯一标识符作为载荷的一部分。 ```java @Service public class JwtUtil { private String secret = "your_secret_key"; public String generateToken(UserDetails userDetails){ Map<String, Object> claims = new HashMap<>(); return Jwts.builder() .setClaims(claims) .setSubject(userDetails.getUsername()) .setIssuedAt(new Date(System.currentTimeMillis())) .setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 10)) // Expire after 10 hours. .signWith(SignatureAlgorithm.HS512, secret).compact(); } public Boolean validateToken(String token, UserDetails userDetails){ final String username = getUsernameFromToken(token); return (username.equals(userDetails.getUsername()) && !isTokenExpired(token)); } private String getUsernameFromToken(String token){ return getAllClaimsFromToken(token).getSubject(); } private Claims getAllClaimsFromToken(String token){ return Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody(); } private Boolean isTokenExpired(String token){ final Date expiration = getExpirationDateFromToken(token); return expiration.before(new Date()); } private Date getExpirationDateFromToken(String token){ return getAllClaimsFromToken(token).getExpiration(); } } ``` 这段Java程序展示了如何利用`JJWT`库中的工具方法来编码/解码token字符串,并提供了几个辅助函数来进行签名验证其他操作[^4]。 #### 4. 实现过滤器以解析传入HTTP头内的Bearer Token 编写一个实现了`OncePerRequestFilter`接口的新组件,它会在每次收到客户端发送过来的数据包之前自动触发,从而可以从中提取出携带者凭证信息并尝试完成用户身份确认过程。 ```java @Component public class JwtRequestFilter extends OncePerRequestFilter { @Autowired private MyUserDetailsService userDetailsService; @Autowired private JwtUtil jwtUtil; @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)throws ServletException, IOException{ final String authorizationHeader = request.getHeader("Authorization"); String username = null; String jwt = null; if (authorizationHeader != null && authorizationHeader.startsWith("Bearer ")) { jwt = authorizationHeader.substring(7); try { username = jwtUtil.getUsernameFromToken(jwt); } catch(IllegalArgumentException e){ System.out.println("Unable to get JWT Token"); }catch(JwtException e){ System.out.println("JWT token is expired or invalid"); } }else{ logger.warn("couldn't find bearer string, will ignore the header"); } if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) { UserDetails userDetails = this.userDetailsService.loadUserByUsername(username); if (jwtUtil.validateToken(jwt, userDetails)){ UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken( userDetails,null,userDetails.getAuthorities()); authToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); SecurityContextHolder.getContext().setAuthentication(authToken); } } chain.doFilter(request,response); } } ``` 该片段说明了一个典型的拦截链路设计模式的应用场景——即每当有新连接建立时都会先调用此类对象的方法去检查是否存在有效的认证凭据,如果存在,则更新当前线程关联的安全上下文环境以便后续业务层能够获取到已知的身份详情记录[^5]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值