当前位置: 代码网 > it编程>编程语言>Java > 基于数据库 + JWT 的 Spring Boot Security 完整示例代码

基于数据库 + JWT 的 Spring Boot Security 完整示例代码

2026年01月19日 Java 我要评论
基于数据库 + jwt 的 spring boot security 完整示例该示例实现 用户数据库存储 + jwt 无状态认证 + 角色权限控制,适用于前后端分离架构。一、 技术依赖在 pom.xm

基于数据库 + jwt 的 spring boot security 完整示例

该示例实现 用户数据库存储 + jwt 无状态认证 + 角色权限控制,适用于前后端分离架构。

一、 技术依赖

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 驱动 -->
<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 (简化代码) -->
<dependency>
    <groupid>org.projectlombok</groupid>
    <artifactid>lombok</artifactid>
    <optional>true</optional>
</dependency>

二、 数据库设计

设计 sys_user(用户表)、sys_role(角色表)、sys_user_role(用户角色关联表),执行 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
);
-- 用户角色关联表
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)
);
-- 插入测试数据
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: 你的数据库密码
    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小时

2. 实体类

  • 用户实体 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;
}
  • 角色实体 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();
    }
    // 验证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是否过期
    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("用户不存在"));
        // 转换角色为权限
        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 认证过滤器 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);
            // 用户名存在且未认证
            if (username != null && securitycontextholder.getcontext().getauthentication() == null) {
                userdetails userdetails = userdetailsservice.loaduserbyusername(username);
                // 验证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) // 开启方法级权限控制
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() // 前后端分离关闭csrf
                .sessionmanagement().sessioncreationpolicy(sessioncreationpolicy.stateless) // 无状态
                .and()
                .authorizehttprequests()
                .antmatchers("/auth/login").permitall() // 登录接口公开
                .anyrequest().authenticated(); // 其他接口需认证
        // 添加jwt过滤器
        http.addfilterbefore(jwtauthenticationfilter, usernamepasswordauthenticationfilter.class);
        return http.build();
    }
}

7. 登录控制器与测试接口

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) {
        // 认证用户
        authenticationmanager.authenticate(new usernamepasswordauthenticationtoken(username, password));
        // 生成token
        userdetails userdetails = userdetailsservice.loaduserbyusername(username);
        return jwtutil.generatetoken(userdetails);
    }
}
// 测试接口
@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. 仓库接口 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);
}

四、 测试步骤

  1. 启动项目,使用 postman 调用 post /auth/login?username=admin&password=123456 获取 token。
  2. 调用测试接口时,在请求头添加 authorization: bearer 生成的token
  3. 访问 /test/admin 需 admin 角色,访问 /test/user 需 user 角色,无权限或 token 失效会返回 403/401。

到此这篇关于基于数据库 + jwt 的 spring boot security 完整示例代码的文章就介绍到这了,更多相关spring boot security jwt内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2026  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com