SpringBootToken详解

随着互联网的快速发展,越来越多的应用程序需要用户进行注册、登录和权限管理。使用SpringBootToken可以实现安全的用户管理,保护敏感资源和数据。在本篇文章中,我们将从多个方面介绍SpringBootToken的使用和相关知识。

一、SpringBootToken登录

用户登录是使用SpringBootToken的第一步,它需要验证用户的身份信息是否正确。Spring中提供了一个JWT(JSON Web Token)框架,可以通过JWT实现用户登录认证。

JWT作为一种简洁的、自包含的格式可以在接收方之间传递信息。JWT由三部分组成:header、payload和signature。header部分通常由该JWT的类型和所使用的签名算法组成。payload部分包含了用户的信息和JWT的过期时间。signature则是根据header、payload以及密钥生成的哈希值。通过组合这三部分数据,就可以生成JWT。

下面是一个SpringBootToken的登录代码示例:

//依赖

  io.jsonwebtoken
  jjwt
  0.7.0


//生成Token
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Component
public class JwtTokenUtil {
    private static final String CLAIM_KEY_USERNAME = "sub";
    private static final String CLAIM_KEY_CREATED = "created";
    @Value("${jwt.secret}")
    private String secret;
    @Value("${jwt.expiration}")
    private Long expiration;

    /**
     * 通过用户名生成Token
     * @param username 用户名
     * @return Token
     */
    public String generateToken(String username) {
        Claims claims = Jwts.claims().setSubject(username);
        Date now = new Date();
        Date expirationDate = new Date(now.getTime() + expiration * 1000);
        claims.put(CLAIM_KEY_CREATED, now);
        return Jwts.builder()
                .setClaims(claims)
                .setExpiration(expirationDate)
                .signWith(SignatureAlgorithm.HS512, secret)
                .compact();
    }

    /**
     * 从Token中获取用户名
     * @param token Token
     * @return 用户名
     */
    public String getUsernameFromToken(String token) {
        String username;
        try {
            Claims claims = getClaimsFromToken(token);
            username = claims.getSubject();
        } catch (Exception e) {
            username = null;
        }
        return username;
    }

    /**
     * 验证Token是否合法
     * @param token Token
     * @return 是否合法
     */
    public boolean validateToken(String token) {
        return !isTokenExpired(token);
    }

    /**
     * 验证Token是否过期
     * @param token Token
     * @return 是否过期
     */
    private boolean isTokenExpired(String token) {
        Date expiration = getExpirationDateFromToken(token);
        return expiration.before(new Date());
    }

    /**
     * 从Token中获取Token过期时间
     * @param token Token
     * @return Token过期时间
     */
    private Date getExpirationDateFromToken(String token) {
        Claims claims = getClaimsFromToken(token);
        return claims.getExpiration();
    }

    /**
     * 从Token中获取Claims
     * @param token Token
     * @return Claims
     */
    private Claims getClaimsFromToken(String token) {
        Claims claims;
        try {
            claims = Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody();
        } catch (Exception e) {
            claims = null;
        }
        return claims;
    }
}

二、SpringBootToken共享

在一些分布式应用中,我们希望将Token存储在外部的系统中,并通过其他服务来验证Token。这时候我们需要保证Token的一致性,即任何由一个服务生成的Token都可以被其他服务验证通过。

为了实现Token的共享,我们可以使用公共的密钥来对Token进行签名和验证。所有需要使用Token的服务都使用相同的公共密钥来实现签名和验证。下面是使用公共密钥来实现Token共享的代码示例:

//依赖

  io.jsonwebtoken
  jjwt
  0.7.0


//生成Token
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.stereotype.Component;

@Component
public class JwtTokenUtil {
    private static final String CLAIM_KEY_USERNAME = "sub";
    private static final String CLAIM_KEY_CREATED = "created";
    private static final String CLAIM_KEY_AUDIENCE = "audience";
    private static final String AUDIENCE_UNKNOWN = "unknown";
    private static final String AUDIENCE_WEB = "web";
    private static final String AUDIENCE_MOBILE = "mobile";
    @Value("${jwt.secret}")
    private String secret;
    @Value("${jwt.expiration}")
    private Long expiration;

    /**
     * 根据用户和设备生成Token
     * @param username 用户名
     * @param audience 设备
     * @return Token
     */
    public String generateToken(String username, String audience) {
        if (StringUtils.isEmpty(audience)) {
            audience = AUDIENCE_UNKNOWN;
        }
        Claims claims = Jwts.claims().setSubject(username);
        claims.put(CLAIM_KEY_CREATED, new Date());
        claims.put(CLAIM_KEY_AUDIENCE, audience);
        Date now = new Date();
        Date expirationDate = new Date(now.getTime() + expiration * 1000);
        return Jwts.builder()
                .setClaims(claims)
                .setExpiration(expirationDate)
                .signWith(SignatureAlgorithm.HS512, secret)
                .compact();
    }

    /**
     * 从Token中获取用户名
     * @param token Token
     * @return 用户名
     */
    public String getUsernameFromToken(String token) {
        String username;
        try {
            Claims claims = getClaimsFromToken(token);
            username = claims.getSubject();
        } catch (Exception e) {
            username = null;
        }
        return username;
    }

    /**
     * 从Token中获取Token过期时间
     * @param token Token
     * @return Token过期时间
     */
    public Date getExpirationDateFromToken(String token) {
        Claims claims = getClaimsFromToken(token);
        return claims.getExpiration();
    }

    /**
     * 验证Token是否合法
     * @param token Token
     * @param userDetails 用户
     * @return 是否合法
     */
    public boolean validateToken(String token, UserDetails userDetails) {
        String username = getUsernameFromToken(token);
        return (username.equals(userDetails.getUsername()) && !isTokenExpired(token));
    }

    /**
     * 验证Token是否过期
     * @param token Token
     * @return 是否过期
     */
    private boolean isTokenExpired(String token) {
        Date expiration = getExpirationDateFromToken(token);
        return expiration.before(new Date());
    }

    /**
     * 从Token中获取Claims
     * @param token Token
     * @return Claims
     */
    private Claims getClaimsFromToken(String token) {
        Claims claims;
        try {
            claims = Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody();
        } catch (Exception e) {
            claims = null;
        }
        return claims;
    }
}

三、SpringBootToken校验

在使用SpringBootToken时,安全性非常重要,我们需要对Token进行校验。校验的目的是验证Token的有效性,即Token是否有效、是否被篡改过等。

SpringBootToken提供了一种很方便的方式来进行Token的校验,即使用拦截器来拦截访问,然后进行Token校验。下面是一个SpringBootToken校验的代码示例:

/**
 * Token拦截器
 */
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {

    @Autowired
    private UserDetailsService userDetailsService;
    @Autowired
    private JwtTokenUtil jwtTokenUtil;
    @Value("${jwt.header}")
    private String header;
    @Value("${jwt.tokenPrefix}")
    private String tokenPrefix;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException {
        String token = request.getHeader(header);
        if (token != null && token.startsWith(tokenPrefix)) {
            token = token.substring(tokenPrefix.length());
            String username = jwtTokenUtil.getUsernameFromToken(token);
            if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
                UserDetails userDetails = this.userDetailsService.loadUserByUsername(username);
                if (jwtTokenUtil.validateToken(token, userDetails)) {
                    UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
                    authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
                    SecurityContextHolder.getContext().setAuthentication(authentication);
                }
            }
        }
        chain.doFilter(request, response);
    }
}

四、SpringBootToken放行

虽然SpringBootToken提供了很好的安全性,但在某些情况下,我们需要放行一些不需要身份认证的资源。与其他的Spring安全机制一样,SpringBootToken也提供了很好的支持来实现这一目的。

我们可以在WebSecurityConfigurerAdapter中配置用于放行的资源以及需要进行身份验证的资源。下面是一个配置文件的示例:

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    private JwtAuthenticationEntryPoint authenticationEntryPoint;
    @Autowired
    private JwtUserDetailsService userDetailsService;
    @Autowired
    private JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;
    @Value("${jwt.header}")
    private String header;

    @SuppressWarnings({"rawtypes", "unchecked"})
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
    }

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

    @Override
    @Bean
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()
                .exceptionHandling().authenticationEntryPoint(authenticationEntryPoint).and()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
                .authorizeRequests()
                .antMatchers("/auth/**").permitAll()
                .anyRequest().authenticated();
        http.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
        http.headers().cacheControl();
    }

    @Bean
    public JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter() {
        return new JwtAuthenticationTokenFilter();
    }

    @Bean
    public JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint() {
        return new JwtAuthenticationEntryPoint();
    }

    /**
     * 忽略静态资源拦截
     * @param web
     * @throws Exception
     */
    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/static/**");
    }
}

五、SpringBootToken用什么比较好选取

在选择使用什么框架来实现用户登录和授权时,可以根据实际情况来选择。SpringBootToken提供了很好的支持来实现用户登录认证、Token的生成和验证、Token的共享和资源的放行,使用起来非常方便。

如果您的应用程序需要更多的功能,或者需要更高级的安全性,可以考虑使用其他框架,如Shiro、OAuth2等。这些框架提供了更丰富的授权和权限管理功能,同时也需要更多的配置和实现。

总之,在选择框架时,需要根据实际情况来选择,同时也需要考虑到自己的技术水平和开发成本。

六、总结

在本文中,我们详细介绍了SpringBootToken的使用和相关知识。SpringBootToken不仅可以实现安全的用户管理,还可以保护敏感资源和数据,保证应用程序的安全性。在使用SpringBootToken时,我们需要考虑安全性、代码复杂性、开发成本等方面的因素来选择合适的框架。

原创文章,作者:小蓝,如若转载,请注明出处:https://www.506064.com/n/248750.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
小蓝小蓝
上一篇 2024-12-12 13:29
下一篇 2024-12-12 13:29

相关推荐

  • Linux sync详解

    一、sync概述 sync是Linux中一个非常重要的命令,它可以将文件系统缓存中的内容,强制写入磁盘中。在执行sync之前,所有的文件系统更新将不会立即写入磁盘,而是先缓存在内存…

    编程 2025-04-25
  • 神经网络代码详解

    神经网络作为一种人工智能技术,被广泛应用于语音识别、图像识别、自然语言处理等领域。而神经网络的模型编写,离不开代码。本文将从多个方面详细阐述神经网络模型编写的代码技术。 一、神经网…

    编程 2025-04-25
  • git config user.name的详解

    一、为什么要使用git config user.name? git是一个非常流行的分布式版本控制系统,很多程序员都会用到它。在使用git commit提交代码时,需要记录commi…

    编程 2025-04-25
  • Python安装OS库详解

    一、OS简介 OS库是Python标准库的一部分,它提供了跨平台的操作系统功能,使得Python可以进行文件操作、进程管理、环境变量读取等系统级操作。 OS库中包含了大量的文件和目…

    编程 2025-04-25
  • Linux修改文件名命令详解

    在Linux系统中,修改文件名是一个很常见的操作。Linux提供了多种方式来修改文件名,这篇文章将介绍Linux修改文件名的详细操作。 一、mv命令 mv命令是Linux下的常用命…

    编程 2025-04-25
  • Python输入输出详解

    一、文件读写 Python中文件的读写操作是必不可少的基本技能之一。读写文件分别使用open()函数中的’r’和’w’参数,读取文件…

    编程 2025-04-25
  • 详解eclipse设置

    一、安装与基础设置 1、下载eclipse并进行安装。 2、打开eclipse,选择对应的工作空间路径。 File -> Switch Workspace -> [选择…

    编程 2025-04-25
  • MPU6050工作原理详解

    一、什么是MPU6050 MPU6050是一种六轴惯性传感器,能够同时测量加速度和角速度。它由三个传感器组成:一个三轴加速度计和一个三轴陀螺仪。这个组合提供了非常精细的姿态解算,其…

    编程 2025-04-25
  • C语言贪吃蛇详解

    一、数据结构和算法 C语言贪吃蛇主要运用了以下数据结构和算法: 1. 链表 typedef struct body { int x; int y; struct body *nex…

    编程 2025-04-25
  • Java BigDecimal 精度详解

    一、基础概念 Java BigDecimal 是一个用于高精度计算的类。普通的 double 或 float 类型只能精确表示有限的数字,而对于需要高精度计算的场景,BigDeci…

    编程 2025-04-25

发表回复

登录后才能评论