Spring Boot + Spring Security JWT权限鉴权系统

本文介绍了如何使用Spring Boot结合Spring Security和JWT实现登录认证及动态权限控制。详细阐述了认证流程、项目技术栈、数据库设计、核心类开发以及异常处理,并提供了登录接口的测试示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

安全框架

  • Spring Boot整合Spring Security JWT实现登录认证以及权限认证
Spring Security
  • 简介

    1. SpringSecurity是一个用于Java 企业级应用程序的安全框架(简单说是对访问权限进行控制)
    2. 应用的安全性包括用户认证(Authentication)和用户授权(Authorization)
  • 认证过程

  • Spring Security 的认证过程

    1. (前端)用户使用用户名和密码进行登录。
    2. (后端)Spring Security 将获取到的用户名和密码封装成一个实现了 Authentication 接口的 UsernamePasswordAuthenticationToken。
    3. (后端)将上述产生的 token 对象传递给 AuthenticationManager 进行登录认证。
    4. (后端)AuthenticationManager 认证成功后将会返回一个封装了用户权限等信息的 Authentication 对象。
    5. (后端)通过调用 SecurityContextHolder.getContext().setAuthentication(…) 将 AuthenticationManager 返回的 Authentication 对象赋予给当前的 SecurityContext。
  • 在认证成功后,用户就可以继续操作去访问其它受保护的资源了,但是在访问的时候将会使用保存在 SecurityContext 中的 Authentication 对象进行相关的权限鉴定。

  • 流程展示

  • 登录流程
    在这里插入图片描述

  • 接口验证流程
    在这里插入图片描述

搭建项目
  • 技术栈

数据库: mysql 8.x
连接池: druid
持久层框架: MyBatis-plus
安全框架: Spring Security
安全传输工具: JWT
Json解析: fastjson

  • 新建Spring Boot工程
导入依赖和配置
  1. pom.xml中,引入相关依赖
 <!-- web 依赖-->
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <!--    lombok 依赖-->
    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
    </dependency>

    <!--    mysql 依赖-->
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <scope>runtime</scope>
    </dependency>

    <!--整合mybatis plus https://baomidou.com/-->
    <dependency>
      <groupId>com.baomidou</groupId>
      <artifactId>mybatis-plus-boot-starter</artifactId>
      <version>3.5.1</version>
    </dependency>

    <!-- druid 连接池 -->
    <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>druid</artifactId>
      <version>1.2.8</version>
    </dependency>

    <!--    hutool 工具类)-->
    <dependency>
      <groupId>cn.hutool</groupId>
      <artifactId>hutool-all</artifactId>
      <version>5.3.3</version>
    </dependency>

    <!-- springboot security -->
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-security</artifactId>
    </dependency>

    <!--jackson-->
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-databind</artifactId>
      <version>2.11.4</version>
    </dependency>

    <!-- jwt -->
    <dependency>
      <groupId>io.jsonwebtoken</groupId>
      <artifactId>jjwt</artifactId>
      <version>0.9.1</version>
    </dependency>

    <!--    redis 依赖-->
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>

    <dependency>
      <groupId>org.apache.commons</groupId>
      <artifactId>commons-lang3</artifactId>
      <version>3.11</version>
    </dependency>

    <!--    swagger2依赖-->
    <dependency>
      <groupId>io.springfox</groupId>
      <artifactId>springfox-swagger2</artifactId>
      <version>2.7.0</version>
    </dependency>

    <!--    swagger 第三方ui依赖-->
    <dependency>
      <groupId>com.github.xiaoymin</groupId>
      <artifactId>swagger-bootstrap-ui</artifactId>
      <version>1.9.6</version>
    </dependency>

    <!--    谷歌验证码 kaptcha-->
    <dependency>
      <groupId>com.github.penggle</groupId>
      <artifactId>kaptcha</artifactId>
      <version>2.3.2</version>
    </dependency>
  1. 配置文件 application.yml
# 开发环境配置文件
server:
  port: 9090

spring:
  #  配置数据源
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver  #数据库链接驱动
    url: jdbc:mysql://localhost:3306/base?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai #url
    username: root  #用户名
    password: root1234  #密码
    #Druid数据源配置
    type: com.alibaba.druid.pool.DruidDataSource
    druid:
      initial-size: 10 #初始化时建立物理连接的个数
      min-idle: 5 #最小连接池数量
      maxActive: 30 #最大连接池数量
      maxWait: 60000 #获取连接时最大等待时间,单位毫秒

# mybatis-plus 配置
mybatis-plus:
  #  配置mapper映射文件
  mapper-locations: classpath*:/mapper/*Mapper.xml
  type-aliases-package: com.fang.system.entity
  configuration:
    # 自动驼峰命名
    map-underscore-to-camel-case: true

  # mybatis sql打印(方法接口所在的包,不是mapper.xml文件所在的包)
logging:
  level:
    com.example.admin.mapper: debug

# Redis配置
  redis:
    host: 127.0.0.1    #服务器地址
    port: 6379    #服务器端口
    database: 0   #数据库
    password:   #密码
    timeout: 100000ms   #超时时间
    lettuce:
      pool:
        max-active: 1024    #最大连接数
        max-wait: 10000ms   #最大连接阻塞时间 默认-1
        max-idle: 200    #最大空闲连接
        min-idle: 5     #最小空闲连接

# jwt 配置
jwt:
  tokenHeader: Authorization
  tokenHead: Bearer # Token前缀字符
  expiration: 604800 #7天,秒单位
  secret: base-security-secret  # 密匙KEY

动态权限控制
  1. spring security的简单原理

登录验证:

用户登陆,会被AuthenticationProcessingFilter拦截,调用AuthenticationManager的实现,AuthenticationManager会调用ProviderManager来获取用户验证信息(不同的Provider调用的服务不同,因为这些信息可以是在数据库上,可以是在LDAP服务器上,可以是xml配置文件上等);

如果验证通过后会将用户的权限信息封装一个User放到spring的全局缓存SecurityContextHolder中,以备后面访问资源时使用。
访问资源(即授权管理):

访问资源(即授权管理):

访问资源(即授权管理),访问url时,会通过AbstractSecurityInterceptor拦截器拦截,其中会调用FilterInvocationSecurityMetadataSource的方法来获取被拦截url所需的全部权限,在调用授权管理器AccessDecisionManager,这个授权管理器会通过spring的全局缓存SecurityContextHolder获取用户的权限信息,还会获取被拦截的url和被拦截url所需的全部权限,配置权限策略,如果权限足够,则返回,权限不够则报错并调用权限不足页面。

  1. 数据库表设计
    在这里插入图片描述

  2. 权限过滤器 CustomAccessFilter.java

package com.example.admin.filter;

import com.example.admin.entity.Menu;
import com.example.admin.entity.Role;
import com.example.admin.service.IMenuService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;

import java.util.Collection;
import java.util.List;

/**
 * 权限控制
 * @author fangqi174956
 */
@Component
public class CustomAccessFilter implements FilterInvocationSecurityMetadataSource {
   
   
    @Autowired
    private IMenuService menuService;

    private AntPathMatcher antPathMatcher = new AntPathMatcher();

    @Override
    public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException {
   
   
        // 获取请求的url
        String requestUrl = ((FilterInvocation) object).getRequestUrl();
        List<Menu> menus = menuService.getMenusWithRole();

        for (Menu menu : menus) {
   
   
            // 判断请求url 与菜单角色是否匹配
            if(antPathMatcher.match(menu.getUrl(),requestUrl)){
   
   
                String[] roleList = menu.getRoles().stream().map(Role::getUniqueCode).toArray(String[]::new);
                return SecurityConfig.createList(roleList);
            }
        }
        // 没有匹配上的url 默认角色ROLE_login (即登录即可访问)
        return SecurityConfig.createList("ROLE_login");

    }

    @Override
    public Collection<ConfigAttribute> getAllConfigAttributes() {
   
   
        return null;
    }

    @Override
    public boolean supports(Class<?> aClass
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值