最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Spring?Security+JWT如何實(shí)現(xiàn)前后端分離權(quán)限控制

 更新時(shí)間:2025年04月22日 15:26:25   作者:zru_9602  
本篇將手把手教你用?Spring?Security?+?JWT?搭建一套完整的登錄認(rèn)證與權(quán)限控制體系,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

Spring Security+JWT實(shí)現(xiàn)前后端分離權(quán)限控制實(shí)戰(zhàn)

在前后端分離項(xiàng)目中,傳統(tǒng)的基于 Session 的認(rèn)證方式已不再適用。取而代之的是更加輕量、高效的 JWT(JSON Web Token)方式來實(shí)現(xiàn)無狀態(tài)認(rèn)證。

一、為什么要用 JWT?

前后端分離架構(gòu)的挑戰(zhàn):

  • 無法使用 Session 管理登錄狀態(tài)(前端和后端分離、跨域)
  • 需要一種「無狀態(tài)認(rèn)證機(jī)制

JWT 的優(yōu)勢(shì):

  • 無需在服務(wù)端存儲(chǔ)會(huì)話信息(Token 自包含)
  • 結(jié)構(gòu)清晰,支持權(quán)限聲明(claims)
  • 可擴(kuò)展性強(qiáng),可用于 OAuth、SSO 等場(chǎng)景

二、JWT 基本結(jié)構(gòu)

一個(gè) JWT Token 一般分為三段:

Header.Payload.Signature

例如:

eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ1c2VyIiwiaWF0IjoxNjg3NjQ5fQ.K4KgD1sE0JQzA1K6k-FaSd56fQ

每部分作用:

部分內(nèi)容
Header簽名算法,如 HS256
Payload載荷(如用戶名、角色、過期時(shí)間)
Signature簽名(防止篡改)

三、集成 JWT 的 Spring Security 權(quán)限控制思路

整體流程如下:

前端登錄 -> 后端驗(yàn)證用戶 -> 生成 JWT -> 返回給前端 -> 前端每次請(qǐng)求攜帶 Token -> 后端解析驗(yàn)證并授權(quán)

四、核心模塊代碼實(shí)戰(zhàn)

1. 引入依賴(Spring Boot 3.x 示例)

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-api</artifactId>
    <version>0.11.5</version>
</dependency>
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-impl</artifactId>
    <version>0.11.5</version>
    <scope>runtime</scope>
</dependency>
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-jackson</artifactId>
    <version>0.11.5</version>
    <scope>runtime</scope>
</dependency>

2. JWT 工具類

@Component
public class JwtUtil {
    private final String SECRET = "MyJwtSecretKey123"; // 建議放到配置文件中
    private final long EXPIRATION = 1000 * 60 * 60; // 1小時(shí)

    public String generateToken(String username) {
        return Jwts.builder()
            .setSubject(username)
            .setIssuedAt(new Date())
            .setExpiration(new Date(System.currentTimeMillis() + EXPIRATION))
            .signWith(SignatureAlgorithm.HS256, SECRET)
            .compact();
    }

    public String getUsernameFromToken(String token) {
        return Jwts.parser().setSigningKey(SECRET)
            .parseClaimsJws(token).getBody().getSubject();
    }

    public boolean validateToken(String token) {
        try {
            Jwts.parser().setSigningKey(SECRET).parseClaimsJws(token);
            return true;
        } catch (Exception e) {
            return false;
        }
    }
}

3. 自定義登錄接口生成 Token

@RestController
public class AuthController {

    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private JwtUtil jwtUtil;

    @PostMapping("/login")
    public ResponseEntity<?> login(@RequestBody LoginRequest loginRequest) {
        try {
            Authentication auth = authenticationManager.authenticate(
                new UsernamePasswordAuthenticationToken(loginRequest.getUsername(), loginRequest.getPassword())
            );
            String token = jwtUtil.generateToken(loginRequest.getUsername());
            return ResponseEntity.ok(Collections.singletonMap("token", token));
        } catch (AuthenticationException e) {
            return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("用戶名或密碼錯(cuò)誤");
        }
    }
}

4. JWT 認(rèn)證過濾器

@Component
public class JwtAuthFilter extends OncePerRequestFilter {

    @Autowired
    private JwtUtil jwtUtil;

    @Autowired
    private UserDetailsService userDetailsService;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
            throws ServletException, IOException {
        String authHeader = request.getHeader("Authorization");

        if (authHeader != null && authHeader.startsWith("Bearer ")) {
            String token = authHeader.substring(7);
            String username = jwtUtil.getUsernameFromToken(token);

            if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
                UserDetails userDetails = userDetailsService.loadUserByUsername(username);

                if (jwtUtil.validateToken(token)) {
                    UsernamePasswordAuthenticationToken authToken =
                        new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());

                    authToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
                    SecurityContextHolder.getContext().setAuthentication(authToken);
                }
            }
        }

        chain.doFilter(request, response);
    }
}

5. 配置 SecurityFilterChain

@Configuration
@EnableMethodSecurity
public class SecurityConfig {

    @Autowired
    private JwtAuthFilter jwtAuthFilter;

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        return http
            .csrf(csrf -> csrf.disable())
            .authorizeHttpRequests(auth -> auth
                .requestMatchers("/login").permitAll()
                .anyRequest().authenticated()
            )
            .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
            .addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class)
            .build();
    }

    @Bean
    public AuthenticationManager authenticationManager(AuthenticationConfiguration config) throws Exception {
        return config.getAuthenticationManager();
    }
}

五、前端如何配合使用?

  1. 登錄后保存返回的 token
  2. 所有后續(xù)請(qǐng)求在 header 中添加:
Authorization: Bearer <你的 token>

六、權(quán)限控制示例

@RestController
public class UserController {

    @PreAuthorize("hasRole('ADMIN')")
    @GetMapping("/admin/data")
    public String adminData() {
        return "管理員數(shù)據(jù)";
    }

    @PreAuthorize("hasAnyRole('USER','ADMIN')")
    @GetMapping("/user/data")
    public String userData() {
        return "用戶數(shù)據(jù)";
    }
}

總結(jié)

JWT 與 Spring Security 的結(jié)合,可以幫助你構(gòu)建一個(gè)無狀態(tài)、安全、高效的前后端分離權(quán)限系統(tǒng)。它簡(jiǎn)化了登錄狀態(tài)的管理流程,提高了系統(tǒng)的伸縮性與并發(fā)處理能力。

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • springboot配置多數(shù)據(jù)源的一款框架(dynamic-datasource-spring-boot-starter)

    springboot配置多數(shù)據(jù)源的一款框架(dynamic-datasource-spring-boot-starter

    dynamic-datasource-spring-boot-starter 是一個(gè)基于 springboot 的快速集成多數(shù)據(jù)源的啟動(dòng)器,今天通過本文給大家分享這款框架配置springboot多數(shù)據(jù)源的方法,一起看看吧
    2021-09-09
  • 關(guān)于junit測(cè)試需要的依賴

    關(guān)于junit測(cè)試需要的依賴

    這篇文章主要介紹了關(guān)于junit測(cè)試需要的依賴,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-12-12
  • Java8中orElse orElseGet orElseThrow的使用舉例

    Java8中orElse orElseGet orElseThrow的使用舉例

    這篇文章主要介紹了Java8中orElse orElseGet orElseThrow的使用舉例,本文結(jié)合實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧
    2025-09-09
  • Maven編譯Fatal?error?compiling:無效的目標(biāo)發(fā)行版:11問題及解決

    Maven編譯Fatal?error?compiling:無效的目標(biāo)發(fā)行版:11問題及解決

    在Java11中編譯Springboot工程時(shí)遇到問題,解決方法是在pom.xml文件中指定Maven的Java編譯器版本,可以使用MavenJava編譯器屬性或插件,在Java9及以后的版本中,也要使用插件并設(shè)置release屬性
    2024-12-12
  • IO流概述分類字節(jié)流寫數(shù)據(jù)三種方式及問題分析

    IO流概述分類字節(jié)流寫數(shù)據(jù)三種方式及問題分析

    這篇文章主要為大家介紹了IO流概述分類字節(jié)流寫數(shù)據(jù)三種方式及寫數(shù)據(jù)問題分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-12-12
  • MyBatis中的模糊查詢語句

    MyBatis中的模糊查詢語句

    這篇文章主要介紹了MyBatis中的模糊查詢語句的相關(guān)資料,需要的朋友可以參考下
    2017-03-03
  • Intellij IDEA插件開發(fā)入門詳解

    Intellij IDEA插件開發(fā)入門詳解

    這篇文章主要介紹了Intellij IDEA插件開發(fā)入門詳解,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-02-02
  • SpringBoot接口訪問頻率限制的實(shí)現(xiàn)方式

    SpringBoot接口訪問頻率限制的實(shí)現(xiàn)方式

    接口訪問頻率限制是通過在一定時(shí)間內(nèi)限制用戶對(duì)接口的訪問次數(shù)來實(shí)現(xiàn)的,在Spring Boot中,我們可以通過多種方式來實(shí)現(xiàn)接口的限流,如使用過濾器、攔截器或者借助第三方庫,本文給大家講解的非常詳細(xì),需要的朋友可以參考下
    2024-07-07
  • mybatis中association標(biāo)簽的使用解讀

    mybatis中association標(biāo)簽的使用解讀

    這篇文章主要介紹了mybatis中association標(biāo)簽的使用,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-05-05
  • Spring Gateway自定義請(qǐng)求參數(shù)封裝的實(shí)現(xiàn)示例

    Spring Gateway自定義請(qǐng)求參數(shù)封裝的實(shí)現(xiàn)示例

    這篇文章主要介紹了Spring Gateway自定義請(qǐng)求參數(shù)封裝的實(shí)現(xiàn)示例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-09-09

最新評(píng)論

塔河县| 营口市| 安陆市| 桦南县| 马公市| 兴安县| 临朐县| 佛冈县| 濮阳市| 北碚区| 东台市| 海安县| 商水县| 雷山县| 柳州市| 灌阳县| 遂平县| 上杭县| 如东县| 西乌| 正宁县| 繁峙县| 大化| 偏关县| 嘉禾县| 拜泉县| 大新县| 竹山县| 克拉玛依市| 平利县| 金川县| 综艺| 当阳市| 中江县| 农安县| 甘德县| 茌平县| 桐梓县| 彰化市| 睢宁县| 东海县|