第3节-Security用户管理之数据库用户管理

开场白

这一节我们来说说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

这一节就说到这里,我们先来回顾一下这一节的项目结构

第3节 项目结构图

与往节一样,图中红色框框中的是这一节新增或修改的部分,请大家自己对照~

6、运行项目

进入登录页面,输入【LeoLee】与【123456】进行登录~


用户登录前
用户登录后

迷惘不? 彷徨不?惆怅不?抑郁不?迷迷糊糊莫名妙就好用了……。你的方法里甚至只是通过用户名加载了一下用户,然后把用户信息返回去都没有验证就完事儿了

莫慌,下一节我们通过前三节的基础来为大家讲解一下Security的运作原理、BCryptPasswordEncoder加密方式顺路整理一下前几节的代码。

请看下节:04-Security入门

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,294评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,493评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,790评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,595评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,718评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,906评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,053评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,797评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,250评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,570评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,711评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,388评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,018评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,796评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,023评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,461评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,595评论 2 350

推荐阅读更多精彩内容