本文言简意赅,需要有一定的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精简版过滤器链图
刚入门只需要了解三个比较重要的过滤器即可:
1.FilterSecurityInterceptor:方法级权限过滤器,位于过滤器链最低端
2.ExceptionTranslationFilter:异常过滤器,用来处理在认证授权过程中抛出的异常
3.UsernamePasswordAuthenticationFilter:对/login的post请求做拦截,校验表单中的用户名和密码
认证流程图:
完整调用链:官网地址:Architecture :: Spring Security
ChannelProcessingFilterWebAsyncManagerIntegrationFilterSecurityContextPersistenceFilterHeaderWriterFilterCorsFilterCsrfFilterLogoutFilterOAuth2AuthorizationRequestRedirectFilterSaml2WebSsoAuthenticationRequestFilterX509AuthenticationFilterAbstractPreAuthenticatedProcessingFilterCasAuthenticationFilterOAuth2LoginAuthenticationFilterSaml2WebSsoAuthenticationFilterUsernamePasswordAuthenticationFilterOpenIDAuthenticationFilterDefaultLoginPageGeneratingFilterDefaultLogoutPageGeneratingFilterConcurrentSessionFilterDigestAuthenticationFilterBearerTokenAuthenticationFilterBasicAuthenticationFilterRequestCacheAwareFilterSecurityContextHolderAwareRequestFilterJaasApiIntegrationFilterRememberMeAuthenticationFilterAnonymousAuthenticationFilterOAuth2AuthorizationCodeGrantFilterSessionManagementFilterExceptionTranslationFilterFilterSecurityInterceptorSwitchUserFilter
二、准备工作
准备工作非常简单,创建一个springboot项目,引入Spring Security依赖
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId>
</dependency>
随便写一个Controller中的方法,然后启动项目直接调用,会发现地址栏自动跳转到了/login,并提示输入用户名和密码
默认用户名user,密码在控制台里打印
输入后可以发现Controller里的方法已经可以调用,原理其实就是Spring Security包内提供了一系列的默认实现,包括默认用户名密码,默认登录页,默认登录接口等,然后利用SpringBoot的自动装配依次读取并配置。
三、我们要对框架原默认流程做哪些修改
ok,准备工作完成之后,我们思考一个问题,究竟我们要对框架原默认流程做哪些修改?
首先Spring Security默认用户密码是系统生成,这肯定需要改成从数据库中读取。
其次API层面的权限定制化需要我们自己去实现
再有虽然是单体项目,但目前业内大多也都是前后端分离,那么Spring Security原有的session认证传递就不是很好用(前后端分离还需要解决跨域session传递问题,如果后期项目体量变大做了分布式还需要去解决分布式session的问题),所以需要换成业内推崇的JWT(Token)方案。
四、动手实现
登录时序图:
将默认生成的用户名和密码改成查库获取:
新建配置类定制化Spring Security:
自定义JWT拦截器:
登录接口代码片段:
权限认证接口测试:主要还是@PreAuthorize注解,此处应该将权限和接口url的匹配关系写入数据库内,动态从数据库中查询获取,mall-tiny项目有完整实现
数据库SQL:
/*
Navicat MySQL Data TransferSource Server : localhost
Source Server Version : 50719
Source Host : localhost:3306
Source Database : mall_tinyTarget Server Type : MYSQL
Target Server Version : 50719
File Encoding : 65001Date: 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前端,开箱即用。