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/zh-hant/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

發表回復

登錄後才能評論