本文言简意赅,需要有一定的Java编程基础,说再多也不如直接撸代码,文末附SpringSecurity + JWT Demo和Github开源项目 mall-tiny 完成实现方案以供参考。直接看代码有疑惑的同学推荐两个B站免费的教学视频:

​尚硅谷SpringSecurity框架教程(spring security源码剖析从入门到精通)_哔哩哔哩_bilibili​

​SpringSecurity框架教程-SpringSecurity+JWT实现项目级前端分离认证授权-B站最通俗易懂的SpringSecurity课程_哔哩哔哩_bilibili​

一、Spring Security简介

Spring Security是一款可定制的身份验证和访问控制框架,是Spring应用程序的标准安全框架。其核心就是一组过滤器链。

Spring Security精简版过滤器链图单体架构下的认证授权方案 - SpringSecurity + JWT_JWT

刚入门只需要了解三个比较重要的过滤器即可:

1.FilterSecurityInterceptor:方法级权限过滤器,位于过滤器链最低端

2.ExceptionTranslationFilter:异常过滤器,用来处理在认证授权过程中抛出的异常

3.UsernamePasswordAuthenticationFilter:对/login的post请求做拦截,校验表单中的用户名和密码

认证流程图:

单体架构下的认证授权方案 - SpringSecurity + JWT_spring_02

完整调用链:官网地址:​​Architecture :: Spring Security​

ChannelProcessingFilter

WebAsyncManagerIntegrationFilter

SecurityContextPersistenceFilter

HeaderWriterFilter

CorsFilter

CsrfFilter

LogoutFilter

OAuth2AuthorizationRequestRedirectFilter

Saml2WebSsoAuthenticationRequestFilter

X509AuthenticationFilter

AbstractPreAuthenticatedProcessingFilter

CasAuthenticationFilter

OAuth2LoginAuthenticationFilter

Saml2WebSsoAuthenticationFilter

UsernamePasswordAuthenticationFilter

OpenIDAuthenticationFilter

DefaultLoginPageGeneratingFilter

DefaultLogoutPageGeneratingFilter

ConcurrentSessionFilter

DigestAuthenticationFilter

BearerTokenAuthenticationFilter

BasicAuthenticationFilter

RequestCacheAwareFilter

SecurityContextHolderAwareRequestFilter

JaasApiIntegrationFilter

RememberMeAuthenticationFilter

AnonymousAuthenticationFilter

OAuth2AuthorizationCodeGrantFilter

SessionManagementFilter

ExceptionTranslationFilter

FilterSecurityInterceptor

SwitchUserFilter

二、准备工作

准备工作非常简单,创建一个springboot项目,引入Spring Security依赖

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

随便写一个Controller中的方法,然后启动项目直接调用,会发现地址栏自动跳转到了/login,并提示输入用户名和密码

单体架构下的认证授权方案 - SpringSecurity + JWT_JAVA_03

 默认用户名user,密码在控制台里打印

单体架构下的认证授权方案 - SpringSecurity + JWT_JAVA_04

 输入后可以发现Controller里的方法已经可以调用,原理其实就是Spring Security包内提供了一系列的默认实现,包括默认用户名密码,默认登录页,默认登录接口等,然后利用SpringBoot的自动装配依次读取并配置。

三、我们要对框架原默认流程做哪些修改

ok,准备工作完成之后,我们思考一个问题,究竟我们要对框架原默认流程做哪些修改?

首先Spring Security默认用户密码是系统生成,这肯定需要改成从数据库中读取。

其次API层面的权限定制化需要我们自己去实现

再有虽然是单体项目,但目前业内大多也都是前后端分离,那么Spring Security原有的session认证传递就不是很好用(前后端分离还需要解决跨域session传递问题,如果后期项目体量变大做了分布式还需要去解决分布式session的问题),所以需要换成业内推崇的JWT(Token)方案。

四、动手实现

登录时序图:

单体架构下的认证授权方案 - SpringSecurity + JWT_JWT_05

 将默认生成的用户名和密码改成查库获取:

单体架构下的认证授权方案 - SpringSecurity + JWT_JAVA_06

新建配置类定制化Spring Security:

单体架构下的认证授权方案 - SpringSecurity + JWT_JAVA_07

单体架构下的认证授权方案 - SpringSecurity + JWT_JWT_08

 自定义JWT拦截器:

单体架构下的认证授权方案 - SpringSecurity + JWT_用户名_09

 登录接口代码片段:

单体架构下的认证授权方案 - SpringSecurity + JWT_spring_10

权限认证接口测试:主要还是@PreAuthorize注解,此处应该将权限和接口url的匹配关系写入数据库内,动态从数据库中查询获取,mall-tiny项目有完整实现

单体架构下的认证授权方案 - SpringSecurity + JWT_用户名_11

 数据库SQL:

/*
Navicat MySQL Data Transfer

Source Server : localhost
Source Server Version : 50719
Source Host : localhost:3306
Source Database : mall_tiny

Target Server Type : MYSQL
Target Server Version : 50719
File Encoding : 65001

Date: 2020-08-24 14:06:42
*/

SET FOREIGN_KEY_CHECKS=0;

-- ----------------------------
-- Table structure for ums_admin
-- ----------------------------
DROP TABLE IF EXISTS `ums_admin`;
CREATE TABLE `ums_admin` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`username` varchar(64) DEFAULT NULL,
`password` varchar(64) DEFAULT NULL,
`icon` varchar(500) DEFAULT NULL COMMENT '头像',
`email` varchar(100) DEFAULT NULL COMMENT '邮箱',
`nick_name` varchar(200) DEFAULT NULL COMMENT '昵称',
`note` varchar(500) DEFAULT NULL COMMENT '备注信息',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`login_time` datetime DEFAULT NULL COMMENT '最后登录时间',
`status` int(1) DEFAULT '1' COMMENT '帐号启用状态:0->禁用;1->启用',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=16 DEFAULT CHARSET=utf8 COMMENT='后台用户表';

-- ----------------------------
-- Records of ums_admin
-- ----------------------------
INSERT INTO `ums_admin` VALUES ('1', 'test', '$2a$10$NZ5o7r2E.ayT2ZoxgjlI.eJ6OEYqjH7INR/F.mXDbjZJi9HF0YCVG', 'http://macro-oss.oss-cn-shenzhen.aliyuncs.com/mall/images/20180607/timg.jpg', 'test@qq.com', '测试账号', null, '2018-09-29 13:55:30', '2018-09-29 13:55:39', '1');
INSERT INTO `ums_admin` VALUES ('3', 'admin', '$2a$10$rNGcsXjfhVgJ9wJwOoaalO3XJ5GRTZWVFVFA9e0kPKb/YaOBgwtk.', 'http://macro-oss.oss-cn-shenzhen.aliyuncs.com/mall/images/20180607/timg.jpg', 'admin@163.com', '系统管理员', '系统管理员', '2018-10-08 13:32:47', '2019-04-20 12:45:16', '1');
INSERT INTO `ums_admin` VALUES ('4', 'macro', '$2a$10$Bx4jZPR7GhEpIQfefDQtVeS58GfT5n6mxs/b4nLLK65eMFa16topa', 'string', 'macro@qq.com', 'macro', 'macro专用', '2019-10-06 15:53:51', '2020-02-03 14:55:55', '1');
INSERT INTO `ums_admin` VALUES ('6', 'productAdmin', '$2a$10$6/.J.p.6Bhn7ic4GfoB5D.pGd7xSiD1a9M6ht6yO0fxzlKJPjRAGm', null, 'product@qq.com', '商品管理员', '只有商品权限', '2020-02-07 16:15:08', null, '1');
INSERT INTO `ums_admin` VALUES ('7', 'orderAdmin', '$2a$10$UqEhA9UZXjHHA3B.L9wNG.6aerrBjC6WHTtbv1FdvYPUI.7lkL6E.', null, 'order@qq.com', '订单管理员', '只有订单管理权限', '2020-02-07 16:15:50', null, '1');
INSERT INTO `ums_admin` VALUES ('10', 'ceshi', '$2a$10$RaaNo9CC0RSms8mc/gJpCuOWndDT4pHH0u5XgZdAAYFs1Uq4sOPRi', null, 'ceshi@qq.com', 'ceshi', null, '2020-03-13 16:23:30', null, '1');

默认账号admin/admin

五、项目工程地址

​博主DEMO地址:https://github.com/L1021204735/SpringSecurity-JWT​

​mall-tiny项目地址:GitHub - macrozheng/mall-tiny: mall-tiny是一款基于SpringBoot+MyBatis-Plus的快速开发脚手架,拥有完整的权限管理功能,可对接Vue前端,开箱即用。​