在前端的文章中,我们实现了使用 SpringSecurity 实现登录鉴权,并使用数据库存储用户信息,实现登录鉴权
SpringBoot2.0实战(16)整合SpringSecurity之最简登录方法鉴权
SpringBoot2.0实战(17)整合SpringSecurity基于数据库登录鉴权
登录页都是使用 SpringSecurity 提供的默认登录,入参为 username 及 password,前端通过 form 表单提交请求,后台使用 request.getParameter() 获取填写数据。
目前,在实际项目中,更多的企业选择使用前后端分离的项目架构,前后端数据交互选择使用 application/json 方式进行传递,同时,在实际的项目中,拥有更多形式的登录,比如手机号/短信验证码,不能使用单一的 usernamepassword 结构进行处理,需要自行定义入参结构。
目标
本章将整合 SpringSecurity 实现使用自定义格式进行登录,并使用 json 方式进行前后端交互。
准备工作
创建用户表 user、角色表 role、用户角色关系表 user_role
CREATE TABLE `s_role` (
`ID` int(11) NOT NULL AUTO_INCREMENT,
`CREATE_ID` int(11) DEFAULT NULL,
`CREATE_TIME` datetime DEFAULT NULL,
`UPDATE_ID` int(11) DEFAULT NULL,
`UPDATE_TIME` datetime DEFAULT NULL,
`CODE` varchar(32) COLLATE utf8_bin DEFAULT NULL COMMENT '角色编码',
`ROLE_NAME` varchar(64) COLLATE utf8_bin DEFAULT NULL COMMENT '角色名称',
`STATE` int(2) DEFAULT '1' COMMENT '状态(1启用2禁用)',
PRIMARY KEY (`ID`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='角色表';
CREATE TABLE `s_user` (
`ID` int(11) NOT NULL AUTO_INCREMENT,
`CREATE_ID` int(11) DEFAULT NULL,
`CREATE_TIME` datetime DEFAULT NULL,
`UPDATE_ID` int(11) DEFAULT NULL,
`UPDATE_TIME` datetime DEFAULT NULL,
`USER_NAME` varchar(32) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL COMMENT '用户名',
`PASSWORD` varchar(64) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL COMMENT '密码',
`STATE` int(2) DEFAULT '1' COMMENT '用户状态(-1停用1正常2被锁定)',
PRIMARY KEY (`ID`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='用户表';
CREATE TABLE `s_user_role` (
`ID` int(11) NOT NULL AUTO_INCREMENT,
`CREATE_ID` int(11) DEFAULT NULL,
`CREATE_TIME` datetime DEFAULT NULL,
`USER_ID` int(11) DEFAULT NULL COMMENT '用户外键',
`ROLE_ID` int(11) DEFAULT NULL COMMENT '角色外键',
PRIMARY KEY (`ID`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='用户角色表';
操作步骤
添加依赖
配置
配置一下数据源
编码
实体类
角色实体类 Role,实现权限接口 GrantedAuthority
用户实体类 user,实现权限接口 UserDetails,主要方法是 getAuthorities,用于获取用户的角色列表
用户角色关系实体
Repository 层
分别为三个实体类添加 Mapper
实现 UserDetailsService 接口
UserDetailsService 是 SpringSecurity 提供的登陆时用于根据用户名获取用户信息的接口
自定义登录参数格式
自定义登录过滤器
继承 SpringSecurity 提供的 AbstractAuthenticationProcessingFilter 类,实现 attemptAuthentication 方法,用于登录校验。
本例中,模拟前端使用 json 格式传递参数,所以通过 objectMapper.readValue 的方式从流中获取入参,之后借用了用户名密码登录的校验,并返回权限对象
自定义登陆成功后处理
实现 SpringSecurity 提供的 AuthenticationSuccessHandler 接口,使用 JSON 格式返回
自定义登陆失败后处理
实现 SpringSecurity 提供的 AuthenticationFailureHandler 接口,使用 JSON 格式返回
自定义权限校验失败后处理
登陆成功之后,访问接口之前 SpringSecurity 会进行鉴权,如果没有访问权限,需要对返回进行处理。实现 SpringSecurity 提供的 AccessDeniedHandler 接口,使用 JSON 格式返回
自定义未登录后处理
实现 SpringSecurity 提供的 AuthenticationEntryPoint 接口,使用 JSON 格式返回
注册
在 configure 方法中调用 addFilterAfter 方法,将自定义的 jsonAuthenticationFilter 注册进 SpringSecurity 的过滤器链中。
启动类
验证结果
初始化数据
源码地址
本章源码 : https://github.com/caiyuanzi-song/boot.git
扩展
前面的示例只是使用了一个自定义结构去接收前端表单数据,但是处理还是使用的 username/password 那一套,调用 getAuthenticationManager().authenticate() 去进行入参的校验,AuthenticationManager 中维护一个 AuthenticationProvider 列表,每一个 AuthenticationProvider 会支持一个 Token 类型,username/password 则是使用的 UsernamePasswordAuthenticationToken,并为之提供了 AbstractUserDetailsAuthenticationProvider 进行登录校验,AbstractUserDetailsAuthenticationProvider 的实现类就是 DaoAuthenticationProvider,注册的时候通过 auth.userDetailsService(userService) 方法调用,会将 DaoAuthenticationProvider 加入至 AuthenticationManager 中维护的 AuthenticationProvider 列表中。
如果需要完全自定义入参结构,按如下操作即可
- 自定义 AbstractAuthenticationToken 实现类
- 自定义 AuthenticationProvider 实现类,并支持自定义的 AbstractAuthenticationToken 实现类,具体实现可以参考 AbstractUserDetailsAuthenticationProvider
- 自定义 AuthenticationProcessingFilter 实现类,需要定义请求地址,接收入参,组装 Token,调用 getAuthenticationManager().authenticate()
- 将自定义 AuthenticationProvider 实现类加入至 AuthenticationManager 中维护的 AuthenticationProvider 列表中。
- 将自定义 AuthenticationProcessingFilter 实现类加入至过滤器列表中,置于 UsernamePasswordAuthenticationFilter 之后