开场白
这一节我们来说说Security是如何通过数据库来对用户进行鉴权的,就以目前比较流行的MyBatis+MySQL为例。当然,如果你的ORM层是用JPA或数据库是用Oracle基本也都类似。我这里所用到的MyBatis也是以最简单的方式来使用,因为毕竟这不是一篇讲MyBatis的教程。下面开始啦~如果没有看过前2节的同学可以先翻阅一下前2节的内容:
第1节-SpringBoot整合Security
第2节-Security用户管理之内存用户管理
1、新增Jar包
在POM文件的【properties】中加入如下信息:
<mybatis.version>3.4.6</mybatis.version>
<mybatis-spring.version>1.3.2</mybatis-spring.version>
在POM文件的【dependencies】中加入如下信息:
<!-- mysql -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- mybatis ORM层 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>${mybatis.version}</version>
</dependency>
<!-- mybatis 整合SpringBoot -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>${mybatis-spring.version}</version>
</dependency>
<!-- lombok 简化POJO代码,省去get,set方法,并可生成toString等方法 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
这4个包分别是:
(1)、mysql链接包
(2)、mybatis包
(3)、mybatis与spring-boot整合包
(4)、lombok包,自动生成POJO中的get、set、toString方法,简化日志操作。
2、修改配置文件
修改【src\main\resources】下的配置文件【application.properties】内容:
# mysql
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
#spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/mysecurity5?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=123456
# 开启Mybatis下划线命名转驼峰命名
mybatis.configuration.map-underscore-to-camel-case=true
修改后,启动项目,发现项目可以正常启动。
如果未配置数据库信息的话可能会提示如下错误:
3、创建数据表并写入测试数据
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for sys_user
-- ----------------------------
DROP TABLE IF EXISTS `sys_user`;
CREATE TABLE `sys_user` (
`id` char(36) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '主键,唯一标识',
`loginName` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '登录名',
`loginPwd` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '登录密码',
`nickName` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '用户昵称',
`role` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '角色',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of sys_user
-- ----------------------------
INSERT INTO `sys_user` VALUES ('1', 'LeoLee', '$2a$10$uDQWkXJHI6gEURvnZmpareZYB53Xbe4p6twWITQU/PYZWu95wEI7O', 'Leo', 'USER');
INSERT INTO `sys_user` VALUES ('2', 'KimQu', '$2a$10$S8De83OCGxmVX3Q8nPs.Ou3Pfl6ovzVJrRVAVAXWU6xaRZRopt/qq', 'Kim', 'ADMIN');
4、创建Model、DAO、Service
(1)创建UserModel
@Data
@Alias("userModel")
public class UserModel implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 主键,唯一标识
*/
private String id;
/**
* 登录名
*/
private String loginName;
/**
* 登录密码
*/
private String loginPwd;
/**
* 昵称
*/
private String nickName;
/**
* 用户角色
*/
private String role;
}
PS:为了演示方便,就直接把role丢到user表里吧,在下一节整理代码的时候再把role提出来形成表,然后通过中间表进行映射。
(2)创建UserDAO
@Mapper
@Repository
public interface UserDAO {
@Select("SELECT * FROM sys_user WHERE id = #{id}")
public UserModel load(String id);
@Select("SELECT * FROM sys_user WHERE loginName = #{loginName}")
public UserModel loadByLoginName(String loginName);
}
PS:暂且先把查询语句丢到上面吧,下一节整理代码的时候再将语句放入XML中。
(3)创建UserService接口
public interface UserService {
/**
* 通过主键加载用户
* @param id 主键,唯一标识
* @return 用户对象
*/
public UserModel load(String id);
/**
* 通过登录名加载用户
* @param loginName 登录名
* @return
*/
public UserModel loadByLoginName(String loginName);
}
PS:暂且……你懂的,下一节整理代码的时候封装一下……
(4)创建UserServiceImpl实现类
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserDAO userDAO;
@Override
public UserModel load(String id) {
return userDAO.load(id);
}
@Override
public UserModel loadByLoginName(String loginName) {
return userDAO.loadByLoginName(loginName);
}
}
PS:高兴的话可以写个测试类,不高兴的话就这么着吧……,目测应该可以过……除非哪里出了错……
5、创建及修改Security所需要的类
(1)创建UserDetailsServiceImpl类
@Service("userDetailsService")
public class UserDetailsServiceImpl implements UserDetailsService {
@Autowired
private UserService userService;
@Override
public UserDetails loadUserByUsername(String loginName) throws UsernameNotFoundException {
// 从数据库加载用户信息
UserModel userModel = userService.loadByLoginName(loginName);
// 判断用户是否存在
if( null == userModel ) {
throw new UsernameNotFoundException("用户不存在,请确认后重试~");
}
// 用户角色列表其实就是权限……
Collection<GrantedAuthority> authorities = new ArrayList<>();
authorities.add(new SimpleGrantedAuthority(userModel.getRole() ) );
// 返回UserDetails实现类
return new User(userModel.getLoginName(), userModel.getLoginPwd(), authorities);
}
}
PS:Security要求用户类要实现UserDetailsService接口,其实……其实……也可以直接在UserServiceImpl上进行实现,只是感觉那样偶合性有些高……
(2)修改SecurityConfig配置类
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsService userDetailsService;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
// .withUser("LeoLee").password( "$2a$10$uDQWkXJHI6gEURvnZmpareZYB53Xbe4p6twWITQU/PYZWu95wEI7O").roles("USER")
// .and()
// .withUser("KimQu").password( "$2a$10$S8De83OCGxmVX3Q8nPs.Ou3Pfl6ovzVJrRVAVAXWU6xaRZRopt/qq").roles("ADMIN");
auth.userDetailsService(userDetailsService).passwordEncoder( new BCryptPasswordEncoder() );
}
}
PS:将原来的内存验证注释上,修改为通过userDetailsService进行验证,然后加密方法为BCryptPasswordEncoder
这一节就说到这里,我们先来回顾一下这一节的项目结构
与往节一样,图中红色框框中的是这一节新增或修改的部分,请大家自己对照~
6、运行项目
进入登录页面,输入【LeoLee】与【123456】进行登录~
迷惘不? 彷徨不?惆怅不?抑郁不?迷迷糊糊莫名妙就好用了……。你的方法里甚至只是通过用户名加载了一下用户,然后把用户信息返回去都没有验证就完事儿了
莫慌,下一节我们通过前三节的基础来为大家讲解一下Security的运作原理、BCryptPasswordEncoder加密方式顺路整理一下前几节的代码。
请看下节:04-Security入门