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

基于數(shù)據(jù)庫(kù) + JWT 的 Spring Boot Security 完整示例代碼

 更新時(shí)間:2026年01月19日 10:17:23   作者:jason.zeng@1502207  
該示例展示了如何使用Spring Boot Security和JWT實(shí)現(xiàn)用戶數(shù)據(jù)庫(kù)存儲(chǔ)、無(wú)狀態(tài)認(rèn)證和角色權(quán)限控制,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),感興趣的朋友跟隨小編一起看看吧

基于數(shù)據(jù)庫(kù) + JWT 的 Spring Boot Security 完整示例

該示例實(shí)現(xiàn) 用戶數(shù)據(jù)庫(kù)存儲(chǔ) + JWT 無(wú)狀態(tài)認(rèn)證 + 角色權(quán)限控制,適用于前后端分離架構(gòu)。

一、 技術(shù)依賴

pom.xml 中添加核心依賴:

<!-- Spring Boot Security -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!-- Spring Boot Web -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Spring Boot Data JPA -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- MySQL 驅(qū)動(dòng) -->
<dependency>
    <groupId>com.mysql</groupId>
    <artifactId>mysql-connector-j</artifactId>
    <scope>runtime</scope>
</dependency>
<!-- JWT 依賴 -->
<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>
<!-- Lombok (簡(jiǎn)化代碼) -->
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <optional>true</optional>
</dependency>

二、 數(shù)據(jù)庫(kù)設(shè)計(jì)

設(shè)計(jì) sys_user(用戶表)、sys_role(角色表)、sys_user_role(用戶角色關(guān)聯(lián)表),執(zhí)行 SQL:

CREATE DATABASE IF NOT EXISTS security_jwt;
USE security_jwt;
-- 用戶表
CREATE TABLE sys_user (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    username VARCHAR(50) NOT NULL UNIQUE,
    password VARCHAR(100) NOT NULL,
    status TINYINT DEFAULT 1 COMMENT '1-正常 0-禁用',
    create_time DATETIME DEFAULT CURRENT_TIMESTAMP
);
-- 角色表
CREATE TABLE sys_role (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    role_name VARCHAR(50) NOT NULL,
    role_code VARCHAR(50) NOT NULL UNIQUE
);
-- 用戶角色關(guān)聯(lián)表
CREATE TABLE sys_user_role (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    user_id BIGINT NOT NULL,
    role_id BIGINT NOT NULL,
    FOREIGN KEY (user_id) REFERENCES sys_user(id),
    FOREIGN KEY (role_id) REFERENCES sys_role(id)
);
-- 插入測(cè)試數(shù)據(jù)
INSERT INTO sys_role (role_name, role_code) VALUES ('管理員', 'ROLE_ADMIN'), ('普通用戶', 'ROLE_USER');
-- 密碼是 123456 (BCrypt 加密后)
INSERT INTO sys_user (username, password, status) VALUES 
('admin', '$2a$10$e0wFw5aKz4wLz7xQxXyYz9z8a7b6c5d4e3f2g1h0', 1),
('user', '$2a$10$e0wFw5aKz4wLz7xQxXyYz9z8a7b6c5d4e3f2g1h0', 1);
INSERT INTO sys_user_role (user_id, role_id) VALUES (1,1), (2,2);

三、 核心配置與代碼

1. 配置文件 application.yml

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/security_jwt?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
    username: root
    password: 你的數(shù)據(jù)庫(kù)密碼
    driver-class-name: com.mysql.cj.jdbc.Driver
  jpa:
    hibernate:
      ddl-auto: none
    show-sql: true
    properties:
      hibernate:
        format_sql: true
jwt:
  secret: 7b3a9f8d2e4c6a1b5f9e3c8a2d7b1f4e6c9d8b2a5e7f3c1d4b6a8f9e2c3d5b7a
  expiration: 3600000  # token有效期 1小時(shí)

2. 實(shí)體類

  • 用戶實(shí)體 SysUser.java
package com.example.demo.entity;
import lombok.Data;
import javax.persistence.*;
import java.util.List;
@Data
@Entity
@Table(name = "sys_user")
public class SysUser {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String username;
    private String password;
    private Integer status;
    @ManyToMany(fetch = FetchType.EAGER)
    @JoinTable(
        name = "sys_user_role",
        joinColumns = @JoinColumn(name = "user_id"),
        inverseJoinColumns = @JoinColumn(name = "role_id")
    )
    private List<SysRole> roles;
}
  • 角色實(shí)體 SysRole.java
package com.example.demo.entity;
import lombok.Data;
import javax.persistence.*;
@Data
@Entity
@Table(name = "sys_role")
public class SysRole {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String roleName;
    private String roleCode;
}

3. JWT 工具類 JwtUtil.java

package com.example.demo.util;
import io.jsonwebtoken.*;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
@Component
public class JwtUtil {
    @Value("${jwt.secret}")
    private String secret;
    @Value("${jwt.expiration}")
    private Long expiration;
    // 生成token
    public String generateToken(UserDetails userDetails) {
        Map<String, Object> claims = new HashMap<>();
        return Jwts.builder()
                .setClaims(claims)
                .setSubject(userDetails.getUsername())
                .setIssuedAt(new Date())
                .setExpiration(new Date(System.currentTimeMillis() + expiration))
                .signWith(SignatureAlgorithm.HS512, secret)
                .compact();
    }
    // 驗(yàn)證token
    public boolean validateToken(String token, UserDetails userDetails) {
        String username = getUsernameFromToken(token);
        return username.equals(userDetails.getUsername()) && !isTokenExpired(token);
    }
    // 從token獲取用戶名
    public String getUsernameFromToken(String token) {
        return getClaimsFromToken(token).getSubject();
    }
    // 解析token
    private Claims getClaimsFromToken(String token) {
        return Jwts.parser()
                .setSigningKey(secret)
                .parseClaimsJws(token)
                .getBody();
    }
    // 判斷token是否過(guò)期
    private boolean isTokenExpired(String token) {
        Date expiration = getClaimsFromToken(token).getExpiration();
        return expiration.before(new Date());
    }
}

4. 自定義 UserDetailsService

package com.example.demo.service;
import com.example.demo.entity.SysRole;
import com.example.demo.entity.SysUser;
import com.example.demo.repository.SysUserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.stream.Collectors;
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
    @Autowired
    private SysUserRepository sysUserRepository;
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        SysUser sysUser = sysUserRepository.findByUsername(username)
                .orElseThrow(() -> new UsernameNotFoundException("用戶不存在"));
        // 轉(zhuǎn)換角色為權(quán)限
        List<SimpleGrantedAuthority> authorities = sysUser.getRoles().stream()
                .map(role -> new SimpleGrantedAuthority(role.getRoleCode()))
                .collect(Collectors.toList());
        return new User(sysUser.getUsername(), sysUser.getPassword(), authorities);
    }
}

5. JWT 認(rèn)證過(guò)濾器 JwtAuthenticationFilter.java

package com.example.demo.filter;
import com.example.demo.service.UserDetailsServiceImpl;
import com.example.demo.util.JwtUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {
    @Autowired
    private JwtUtil jwtUtil;
    @Autowired
    private UserDetailsServiceImpl userDetailsService;
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
            throws ServletException, IOException {
        // 獲取token
        String token = request.getHeader("Authorization");
        if (token != null && token.startsWith("Bearer ")) {
            token = token.substring(7);
            String username = jwtUtil.getUsernameFromToken(token);
            // 用戶名存在且未認(rèn)證
            if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
                UserDetails userDetails = userDetailsService.loadUserByUsername(username);
                // 驗(yàn)證token有效性
                if (jwtUtil.validateToken(token, userDetails)) {
                    UsernamePasswordAuthenticationToken authenticationToken =
                            new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
                    authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
                    SecurityContextHolder.getContext().setAuthentication(authenticationToken);
                }
            }
        }
        chain.doFilter(request, response);
    }
}

6. Security 核心配置 SecurityConfig.java

package com.example.demo.config;
import com.example.demo.filter.JwtAuthenticationFilter;
import com.example.demo.service.UserDetailsServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true) // 開(kāi)啟方法級(jí)權(quán)限控制
public class SecurityConfig {
    @Autowired
    private UserDetailsServiceImpl userDetailsService;
    @Autowired
    private JwtAuthenticationFilter jwtAuthenticationFilter;
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
    @Bean
    public AuthenticationManager authenticationManager(HttpSecurity http) throws Exception {
        return http.getSharedObject(AuthenticationManagerBuilder.class)
                .userDetailsService(userDetailsService)
                .passwordEncoder(passwordEncoder())
                .and()
                .build();
    }
    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
                .csrf().disable() // 前后端分離關(guān)閉csrf
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) // 無(wú)狀態(tài)
                .and()
                .authorizeHttpRequests()
                .antMatchers("/auth/login").permitAll() // 登錄接口公開(kāi)
                .anyRequest().authenticated(); // 其他接口需認(rèn)證
        // 添加JWT過(guò)濾器
        http.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
        return http.build();
    }
}

7. 登錄控制器與測(cè)試接口

package com.example.demo.controller;
import com.example.demo.util.JwtUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/auth")
public class AuthController {
    @Autowired
    private AuthenticationManager authenticationManager;
    @Autowired
    private UserDetailsService userDetailsService;
    @Autowired
    private JwtUtil jwtUtil;
    // 登錄接口
    @PostMapping("/login")
    public String login(@RequestParam String username, @RequestParam String password) {
        // 認(rèn)證用戶
        authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(username, password));
        // 生成token
        UserDetails userDetails = userDetailsService.loadUserByUsername(username);
        return jwtUtil.generateToken(userDetails);
    }
}
// 測(cè)試接口
@RestController
@RequestMapping("/test")
public class TestController {
    @GetMapping("/admin")
    @PreAuthorize("hasRole('ROLE_ADMIN')")
    public String adminTest() {
        return "管理員接口";
    }
    @GetMapping("/user")
    @PreAuthorize("hasRole('ROLE_USER')")
    public String userTest() {
        return "普通用戶接口";
    }
}

8. 倉(cāng)庫(kù)接口 SysUserRepository.java

package com.example.demo.repository;
import com.example.demo.entity.SysUser;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.Optional;
public interface SysUserRepository extends JpaRepository<SysUser, Long> {
    Optional<SysUser> findByUsername(String username);
}

四、 測(cè)試步驟

  1. 啟動(dòng)項(xiàng)目,使用 Postman 調(diào)用 POST /auth/login?username=admin&password=123456 獲取 token。
  2. 調(diào)用測(cè)試接口時(shí),在請(qǐng)求頭添加 Authorization: Bearer 生成的token。
  3. 訪問(wèn) /test/admin 需 admin 角色,訪問(wèn) /test/user 需 user 角色,無(wú)權(quán)限或 token 失效會(huì)返回 403/401。

到此這篇關(guān)于基于數(shù)據(jù)庫(kù) + JWT 的 Spring Boot Security 完整示例代碼的文章就介紹到這了,更多相關(guān)Spring Boot Security JWT內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Spring boot中使用Spring-data-jpa方便快捷的訪問(wèn)數(shù)據(jù)庫(kù)(推薦)

    Spring boot中使用Spring-data-jpa方便快捷的訪問(wèn)數(shù)據(jù)庫(kù)(推薦)

    Spring Data JPA 是 Spring 基于 ORM 框架、JPA 規(guī)范的基礎(chǔ)上封裝的一套JPA應(yīng)用框架,可使開(kāi)發(fā)者用極簡(jiǎn)的代碼即可實(shí)現(xiàn)對(duì)數(shù)據(jù)的訪問(wèn)和操作。這篇文章主要介紹了Spring-boot中使用Spring-data-jpa方便快捷的訪問(wèn)數(shù)據(jù)庫(kù),需要的朋友可以參考下
    2018-05-05
  • 基于Spring框架的Shiro配置方法

    基于Spring框架的Shiro配置方法

    這篇文章主要介紹了基于Spring框架的Shiro配置方法,需要的朋友可以參考下
    2014-10-10
  • 最簡(jiǎn)單的在IntelliJ IDEA導(dǎo)入一個(gè)本地項(xiàng)目教程(圖文)

    最簡(jiǎn)單的在IntelliJ IDEA導(dǎo)入一個(gè)本地項(xiàng)目教程(圖文)

    這篇文章主要介紹了最簡(jiǎn)單的在IntelliJ IDEA導(dǎo)入一個(gè)本地項(xiàng)目教程(圖文),文中通過(guò)圖文介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-08-08
  • spring boot自定義配置時(shí)在yml文件輸入有提示問(wèn)題及解決方案

    spring boot自定義配置時(shí)在yml文件輸入有提示問(wèn)題及解決方案

    自定義一個(gè)配置類,然后在yml文件具體配置值時(shí),一般不會(huì)有提示,今天小編給大家分享spring boot自定義配置時(shí)在yml文件輸入有提示問(wèn)題,感興趣的朋友一起看看吧
    2023-10-10
  • Java的設(shè)計(jì)模式之代理模式使用詳解

    Java的設(shè)計(jì)模式之代理模式使用詳解

    這篇文章主要介紹了Java的設(shè)計(jì)模式之代理模式使用詳解,代理模式是23種設(shè)計(jì)模式之一,它關(guān)心的主要是過(guò)程,而不是結(jié)果,代理模式主要提供了對(duì)目標(biāo)對(duì)象的間接訪問(wèn)方式,即通過(guò)代理對(duì)象來(lái)訪問(wèn)目標(biāo)對(duì)象,需要的朋友可以參考下
    2024-01-01
  • Java面試為何阿里強(qiáng)制要求不在foreach里執(zhí)行刪除操作

    Java面試為何阿里強(qiáng)制要求不在foreach里執(zhí)行刪除操作

    那天,小二去阿里面試,面試官老王一上來(lái)就甩給了他一道面試題:為什么阿里的 Java 開(kāi)發(fā)手冊(cè)里會(huì)強(qiáng)制不要在 foreach 里進(jìn)行元素的刪除操作
    2021-11-11
  • SpringBoot整合Web之AOP配置詳解

    SpringBoot整合Web之AOP配置詳解

    面向切面編程(aspect-oriented programming,AOP)主要實(shí)現(xiàn)的目的是針對(duì)業(yè)務(wù)處理過(guò)程中的切面進(jìn)行提取,諸如日志、事務(wù)管理和安全這樣的系統(tǒng)服務(wù),從而使得業(yè)務(wù)邏輯各部分之間的耦合度降低,提高程序的可重用性,同時(shí)提高了開(kāi)發(fā)的效率
    2022-08-08
  • Spring Security動(dòng)態(tài)權(quán)限的實(shí)現(xiàn)方法詳解

    Spring Security動(dòng)態(tài)權(quán)限的實(shí)現(xiàn)方法詳解

    這篇文章主要和小伙伴們簡(jiǎn)單介紹下 Spring Security 中的動(dòng)態(tài)權(quán)限方案,以便于小伙伴們更好的理解 TienChin 項(xiàng)目中的權(quán)限方案,感興趣的可以了解一下
    2022-06-06
  • SpringBoot項(xiàng)目如何打可執(zhí)行war包

    SpringBoot項(xiàng)目如何打可執(zhí)行war包

    最近小編做了一個(gè)springboot項(xiàng)目,最后需要打成war包在容器中部署,下面小編給大家分享下SpringBoot項(xiàng)目如何打可執(zhí)行war包,感興趣的朋友一起看看吧
    2020-04-04
  • Java 是如何讀取和寫入瀏覽器Cookies的實(shí)例詳解

    Java 是如何讀取和寫入瀏覽器Cookies的實(shí)例詳解

    這篇文章主要介紹了Java 是如何讀取和寫入瀏覽器Cookies的實(shí)例的相關(guān)資料,需要的朋友可以參考下
    2016-09-09

最新評(píng)論

邻水| 谢通门县| 松滋市| 大渡口区| 阜城县| 邳州市| 太谷县| 华蓥市| 博湖县| 城固县| 卫辉市| 依兰县| 旺苍县| 邵武市| 柳河县| 麻城市| 城步| 获嘉县| 桃江县| 吉木萨尔县| 临沭县| 柏乡县| 柘荣县| 泰和县| 平湖市| 龙门县| 五家渠市| 开化县| 曲沃县| 曲周县| 普定县| 福海县| 什邡市| 双鸭山市| 黄浦区| 中山市| 浑源县| 会昌县| 焉耆| 浦城县| 洛隆县|