SpringBoot集成Spring Security(1)——入门程序

2023-05-16

本篇文章环境:SpringBoot 2.0 + Mybatis + Spring Security 5.0

注意:SpringSecurity 5.0+ 版本变动较多,且不兼容之前版本,确保你的 SpringBoot 版本为 2.0,能帮你避免掉大部分的坑。


文章目录

    • 一、导入依赖
    • 二、创建数据库
    • 三、准备页面
    • 四、配置application.properties
    • 五、创建实体、Dao、Service和Controller
      • 5.1 实体
      • 5.2 Dao
      • 5.3 Service
      • 5.4 Controller
    • 六、配置SpringSecurity
      • 6.1 UserDetailsService
      • 6.2 WebSecurityConfig
    • 七、运行程序


一、导入依赖

导入 spring-boot-starter-security 依赖,在 SpringBoot 2.0 环境下默认使用的是 5.0 版本。

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

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

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

<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>1.3.1</version>
</dependency>

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
</dependency>

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
</dependency>

二、创建数据库

一般权限控制有三层,即:用户<–>角色<–>权限,用户与角色是多对多,角色和权限也是多对多。这里我们先暂时不考虑权限,只考虑用户<–>角色

创建用户表sys_user

CREATE TABLE `sys_user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) NOT NULL,
  `password` varchar(255) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

创建权限表sys_role

CREATE TABLE `sys_role` (
  `id` int(11) NOT NULL,
  `name` varchar(255) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

创建用户-角色表sys_user_role

CREATE TABLE `sys_user_role` (
  `user_id` int(11) NOT NULL,
  `role_id` int(11) NOT NULL,
  PRIMARY KEY (`user_id`,`role_id`),
  KEY `fk_role_id` (`role_id`),
  CONSTRAINT `fk_role_id` FOREIGN KEY (`role_id`) REFERENCES `sys_role` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
  CONSTRAINT `fk_user_id` FOREIGN KEY (`user_id`) REFERENCES `sys_user` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

初始化一下数据:

INSERT INTO `sys_role` VALUES ('1', 'ROLE_ADMIN');
INSERT INTO `sys_role` VALUES ('2', 'ROLE_USER');

INSERT INTO `sys_user` VALUES ('1', 'admin', '123');
INSERT INTO `sys_user` VALUES ('2', 'zhagnsan', '123');

INSERT INTO `sys_user_role` VALUES ('1', '1');
INSERT INTO `sys_user_role` VALUES ('2', '2');

博主有话说:

这里的权限格式为ROLE_XXX,是Spring Security规定的,不要乱起名字哦!!

三、准备页面

因为是示例程序,页面越简单越好,只用于登陆的login.html以及用于登陆成功后的home.html,将其放置在 resources/static 目录下:

(1)login.html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>登陆</title>
</head>
<body>
<h1>登陆</h1>
<form method="post" action="/login">
    <div>
        用户名:<input type="text" name="username">
    </div>
    <div>
        密码:<input type="password" name="password">
    </div>
    <div>
        <button type="submit">立即登陆</button>
    </div>
</form>
</body>
</html>

博主有话说:

用户的登陆认证是由Spring Security进行处理的,请求路径默认为/login,用户名字段默认为username,密码字段默认为password

(2)home.html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
	<h1>登陆成功</h1>
	<a href="/admin">检测ROLE_ADMIN角色</a>
	<a href="/user">检测ROLE_USER角色</a>
	<button onclick="window.location.href='/logout'">退出登录</button>
</body>
</html>

四、配置application.properties

在配置文件中配置下数据库连接:

spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/security?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8
spring.datasource.username=root
spring.datasource.password=123456

#开启Mybatis下划线命名转驼峰命名
mybatis.configuration.map-underscore-to-camel-case=true

五、创建实体、Dao、Service和Controller

5.1 实体

(1)SysUser

@Data
public class SysUser implements Serializable {
    private Integer id;

    private String name;

    private String password;
}

(2)SysRole

@Data
public class SysRole implements Serializable {
    private Integer id;

    private String name;
}

(3)SysUserRole

@Data
public class SysUserRole implements Serializable {
    private Integer userId;

    private Integer roleId;
}

5.2 Dao

(1)SysUserMapper

@Mapper
public interface SysUserMapper {
    // 根据id查询用户
    @Select("SELECT * FROM sys_user WHERE id = #{id}")
    SysUser selectById(Integer id);

    // 根据用户名查询用户
    @Select("SELECT * FROM sys_user WHERE name = #{name}")
    SysUser selectByName(String name);
}

(2)SysRoleMapper

@Mapper
public interface SysRoleMapper {
    // 根据id查询角色信息
    @Select("SELECT * FROM sys_role WHERE id = #{id}")
    SysRole selectById(Integer id);
}

(3)SysUserRoleMapper

@Mapper
public interface SysUserRoleMapper {
    // 根据用户id查询用户角色表
    @Select("SELECT * FROM sys_user_role WHERE user_id = #{userId}")
    List<SysUserRole> listByUserId(Integer userId);
}

5.3 Service

(1)SysUserService

@Service
public class SysUserService {
    @Autowired
    private SysUserMapper userMapper;

    public SysUser selectById(Integer id) {
        return userMapper.selectById(id);
    }

    public SysUser selectByName(String name) {
        return userMapper.selectByName(name);
    }
}

(2)SysRoleService

@Service
public class SysRoleService {
    @Autowired
    private SysRoleMapper roleMapper;

    public SysRole selectById(Integer id){
        return roleMapper.selectById(id);
    }
}

(3)SysUserService

@Service
public class SysUserService {
    @Autowired
    private SysUserRoleMapper userRoleMapper;

    public List<SysUserRole> listByUserId(Integer userId) {
        return userRoleMapper.listByUserId(userId);
    }
}

5.4 Controller

@Controller
public class LoginController {
    private Logger logger = LoggerFactory.getLogger(LoginController.class);

    @RequestMapping("/")
    public String showHome() {
        String name = SecurityContextHolder.getContext().getAuthentication().getName();
        logger.info("当前登陆用户:" + name);

        return "home.html";
    }

    @RequestMapping("/login")
    public String showLogin() {
        return "login.html";
    }

    @RequestMapping("/admin")
    @ResponseBody
    @PreAuthorize("hasRole('ROLE_ADMIN')")
    public String printAdmin() {
        return "如果你看见这句话,说明你有ROLE_ADMIN角色";
    }

    @RequestMapping("/user")
    @ResponseBody
    @PreAuthorize("hasRole('ROLE_USER')")
    public String printUser() {
        return "如果你看见这句话,说明你有ROLE_USER角色";
    }
}
  • 如代码所示,获取当前登录用户:SecurityContextHolder.getContext().getAuthentication()
  • @PreAuthorize 用于判断用户是否有指定权限,没有就不能访问

六、配置SpringSecurity

6.1 UserDetailsService

首先我们需要自定义 UserDetailsService ,将用户信息和权限注入进来。

我们需要重写 loadUserByUsername 方法,参数是用户输入的用户名。返回值是UserDetails,这是一个接口,一般使用它的子类org.springframework.security.core.userdetails.User,它有三个参数,分别是用户名、密码和权限集。

实际情况下,大多将 DAO 中的 User 类继承 org.springframework.security.core.userdetails.User 返回。

@Service("userDetailsService")
public class CustomUserDetailsService implements UserDetailsService {

    @Autowired
    private SysUserService userService;
    @Autowired
    private SysRoleService roleService;
    @Autowired
    private SysUserRoleService userRoleService;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        Collection<GrantedAuthority> authorities = new ArrayList<>();
        // 从数据库查询用户信息
        SysUser user = userService.selectByName(username);

        if (user == null){
            throw new UsernameNotFoundException("用户不存在");
        }
        // 添加权限
        List<SysUserRole> userRoles = userRoleService.listByUserId(user.getId());
        for (SysUserRole userRole : userRoles) {
            SysRole role = roleService.selectById(userRole.getRoleId());
            authorities.add(new SimpleGrantedAuthority(role.getName()));
        }
        // 返回UserDetails实现类
        return new User(user.getName(), user.getPassword(), authorities);
    }
}

6.2 WebSecurityConfig

该类是 Spring Security 的配置类,该类的三个注解分别是标识该类是配置类、开启 Security 服务、开启全局 Securtiy 注解。

首先将我们自定义的 userDetailsService 注入进来,在 configure() 方法中使用 auth.userDetailsService() 方法替换掉默认的 userDetailsService

这里我们还指定了密码的加密方式(5.0 版本强制要求设置),因为我们数据库是明文存储的,所以明文返回即可,如下所示:

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    private CustomUserDetailsService userDetailsService;

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(new PasswordEncoder() {
            @Override
            public String encode(CharSequence charSequence) {
                return charSequence.toString();
            }

            @Override
            public boolean matches(CharSequence charSequence, String s) {
                return s.equals(charSequence.toString());
            }
        });
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                // 如果有允许匿名的url,填在下面
//                .antMatchers().permitAll()
                .anyRequest().authenticated()
                .and()
                // 设置登陆页
                .formLogin().loginPage("/login")
                // 设置登陆成功页
                .defaultSuccessUrl("/").permitAll()
                // 自定义登陆用户名和密码参数,默认为username和password
//                .usernameParameter("username")
//                .passwordParameter("password")
                .and()
                .logout().permitAll();

        // 关闭CSRF跨域
        http.csrf().disable();
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        // 设置拦截忽略文件夹,可以对静态资源放行
        web.ignoring().antMatchers("/css/**", "/js/**");
    }
}

在这里插入图片描述

七、运行程序

ROLE_ADMIN 账户:用户名 admin,密码 123
ROLE_USER 账户:用户名 zhangsan,密码 123

在这里插入图片描述
注:如果你想要将密码加密,可以修改 configure() 方法如下:

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth.userDetailsService(userDetailsService)
        .passwordEncoder(new BCryptPasswordEncoder());
}

如果有收获!!! 希望老铁们来个三连,点赞、收藏、转发。
创作不易,别忘点个赞,可以让更多的人看到这篇文章,顺便鼓励我写出更好的博客
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

SpringBoot集成Spring Security(1)——入门程序 的相关文章

  • 在IDEA中使用Git往码云(Gitee)上提交代码

    一 IDEA中使用Git上传代码 1 在码云中创建一个仓库 只需要填写一下的信息 xff0c 其他的都不用选 xff1b 创建一个空仓库 此仓库用来提交 xff0c 存储代码 2 设置Git的配置 选择 Git 的安装目录后可以点击 Tes
  • 刚装好的Ubuntu18插上耳机没声音?

    巧了不是 前几天刚经历了Windows10插上耳机没声音的坑 xff0c 今天装了个Ubuntu xff0c 正准备插上耳机开心地学习 结果 xff1f 又没声音 xff1f xff1f xff1f 好吧 xff0c 继续百度解决吧 xff
  • 谷粒学院(二十四)Jenkins+Maven+Github+Springboot实现可持续自动部署(非常详细)

    目录 一 安装内容二 实现过程1 不使用Jenkins2 使用Jenkins 三 准备工作1 Github仓库准备测试项目2 安装java环境 xff08 jdk环境 xff09 3 安装maven环境4 安装Git环境5 安装Docker
  • 谷粒学院【网上教育】总结

    一 项目的启动运行 1 后端项目 将后端项目克隆到本地 xff0c 导入到idea中nacos 在目录下 xff0c 打开bin文件夹 xff0c 双击 startup cmdredis xff0c 在目录下 xff0c 使用cmd xff
  • Navicat Premium 12 卸载和注册表的删除

    卸载就不用我说了 xff0c win10也好 xff0c win7也好直接windows设置里的卸载 xff0c 或者你觉得别的软件卸载的比较干净也行 不过还是不会删掉注册表 xff0c 甚至文件夹都不删除 xff1a 这是卸载 xff0c
  • JDK下载安装及环境变量配置(图片详解)

    一 下载并安装JDK 1 下载 搜索 jdk官方下载 或是直接进入Sun公司的官网 xff08 https www oracle com xff09 下面是JDK版本下载页面 xff1a https www oracle com java
  • 谷粒商城 - 项目环境搭建

    文章目录 1 安装 linux 虚拟机2 安装docker3 docker安装mysql4 docker安装redis5 开发环境统一1 Maven2 Idea amp VsCode 插件3 安装配置git 6 创建git仓库7 创建对应项
  • 《阿里云服务器搭建》------ 安装jdk

    1 首先查看我们linux服务器的操作系统 执行命令 xff1a cat proc version 备注这里是 xff08 x86 64 xff09 表示64位 2 登录Oracle官网 xff0c 下载JDK JDK官网下载 xff1a
  • IDEA连接mysql又报错!Server returns invalid timezone. Go to ‘Advanced‘ tab and set ‘serverTimezone‘

    错误界面 IDEA连接mysql xff0c 地址 xff0c 用户名 xff0c 密码 xff0c 数据库名 xff0c 全都配置好了 xff0c 点测试连接 xff0c 咔 xff01 不成功 xff01 界面是这样的 xff0c 翻译
  • 《阿里云服务器搭建》------ 安装maven

    一 下载压缩包 http maven apache org download cgi 或者百度网盘链接 xff1a https pan baidu com s 1A7bkSGomTrPLtYFq3t5WzQ 提取码 xff1a nro9 二
  • 《阿里云服务器搭建》------ 安装docker

    到docker官网找到对应环境的安装方式如 xff1a https docs docker com engine install centos 1 卸载掉旧版本 yum remove docker span class token punc
  • VM中安装Centos6.8详细步骤(图文)

    目录 1 检查BIOS虚拟化支持2 新建虚拟机3 新建虚拟机向导4 创建虚拟空白光盘5 安装Linux系统对应的CentOS版6 虚拟机命名和定位磁盘位置7 处理器配置 xff0c 看自己是否是双核 多核8 设置内存为2GB9 选择IO控制
  • Ubuntu18:使用CMake-gui编译OpenCV3源码的详细过程

    目录 一 卸载原来的opencv 二 准备工作 三 编译过程 四 测试过程 由于之前安装的OpenCV4与我的代码有多处不兼容 xff0c 所以要重新装一个OpenCV3 xff0c 顺便记录一下过程吧 OpenCV版本 xff1a ope
  • 基于音形码的中文字符串相似度算法(转)

    转自 https blog csdn net chndata article details 41114771 字符串相似度算法是指通过一定的方法 xff0c 来计算两个不同字符串之间的相似程度 通常会用一个百分比来衡量字符串之间的相似程度
  • VMware15中安装Centos7详细步骤(图文)

    文章目录 1 检查虚拟化是否开启2 新建虚拟机3 新建虚拟机向导4 创建虚拟空白光盘5 安装Linux系统对应的CentOS版6 虚拟机命名和定位磁盘位置7 处理器配置 xff0c 看自己是否是双核 多核8 设置内存为2GB9 选择IO控制
  • 设置CentOS7的网卡开机自启动

    1 可以试试这条命令 xff1a CentOS7的网卡开机启动应该是 xff1a systemctl enable network 2 若设置了始终还没有开机启动网络服务 xff0c 最好只好去改配置文件 vim etc sysconfig
  • 谷粒商城 - 架构图

    商城项目地址 xff1a 后端项目源码 xff1a https gitee com StarSea007 gulimall parent 前端项目源码 xff1a https gitee com StarSea007 gulimall vu
  • 牛客网经典120道Java面试常见题(试题+答案)

    牛客网提供了120道Java面试题 xff0c 这里整理出重点的内容 xff0c 而且对答案有疑惑 xff0c 补充了解释内容 xff0c 便于理解 1 什么是Java虚拟机 xff1f 为什么Java被称作是 平台无关的编程语言 xff1
  • Redis面试题(2021最新)

    文章目录 概述什么是RedisRedis有哪些优缺点为什么要用 Redis 为什么要用缓存 为什么要用 Redis 而不用 map guava 做缓存 Redis为什么这么快 数据类型Redis有哪些数据类型Redis的应用场景 持久化什么
  • Java基础知识面试题(2021最新)

    文章目录 1 Java概述什么是Javajdk1 5之后的三大版本JVM JRE和JDK的关系什么是跨平台性 xff1f 原理是什么 xff1f Java语言有哪些特点什么是字节码 xff1f 采用字节码的好处是什么 什么是Java程序的主

随机推荐

  • vagrant up下载centos7慢的解决办法

    安装完vagrant后 执行命令 vagrant init centos 7 进行初始化 会出现一个Vagrantfile文件 然后执行 vagrant up 命令下载centos 7会很慢 将红线里的地址复制到浏览器 xff0c 通过浏览
  • SpringCloud Alibaba 全部组件说明

    文章目录 一 微服务1 系统架构的演变1 xff09 单体应用架构2 xff09 垂直应用架构3 xff09 分布式架构4 xff09 SOA架构5 xff09 微服务架构 2 微服务架构常见的问题3 常见微服务架构 二 SpringClo
  • 前后端分离项目解决跨域问题

    1 跨域概念 跨域 xff1a 指的是浏览器不能执行其他网站的脚本 它是由浏览器的同源策略造成的 xff0c 是 浏览器对javascript施加的安全限制 同源策略 xff1a 是指协议 xff0c 域名 xff0c 端口都要相同 xff
  • ElasticSearch 入门检索的语法和实例【图文】

    文章目录 简介一 基本概念1 Index 索引 2 Type 类型 3 Document 文档 4 倒排索引 二 Docker安装 Es1 下载镜像文件2 创建实例 三 初步检索1 CAT2 索引一个文档 xff08 保存 xff09 3
  • 使用VSCode对libtorch有关的代码cmake时报错:fatal error: torch/script.h: No such file or directory

    最近在Ubuntu上做用libtorch部署深度学习网络的工作 使用IDE是VSCode xff0c 并用cmake进行编译 xff0c 在写demo过程中莫名地出现了如题所示的bug卡了两天 xff0c 今天突然发现问题所在T T xff
  • ConcurrentHashMap实现原理及源码分析

    ConcurrentHashMap是Java并发包中提供的一个线程安全且高效的HashMap实现 xff08 若对HashMap的实现原理还不甚了解 xff0c 可参考我的另一篇文章 HashMap实现原理及源码分析 xff09 xff0c
  • 如何保障mysql和redis之间的数据一致性?

    需求起因 在高并发的业务场景下 xff0c 数据库大多数情况都是用户并发访问最薄弱的环节 所以 xff0c 就需要使用redis做一个缓冲操作 xff0c 让请求先访问到redis xff0c 而不是直接访问MySQL等数据库 这个业务场景
  • SpringCloud(九)GateWay服务网关

    文章目录 1 概述简介1 官网2 是什么3 能干嘛4 微服务架构中网关在哪里5 有Zuul了怎么有出来gateway 2 三大核心概念3 Gateway工作流程4 入门配置1 新建Module2 POM文件3 YML4 主启动类5 9527
  • SpringSecurity框架介绍

    文章目录 1 概要2 历史3 同款产品对比1 Spring Security2 Shiro 4 模块划分 1 概要 Spring 是非常流行和成功的 Java 应用开发框架 xff0c Spring Security 正是 Spring 家
  • SpringSecurity入门案例

    文章目录 1 入门案例演示1 创建一个Springboot项目2 引入相关依赖3 编写Controller进行测试4 运行项目 2 权限管理中的相关概念1 主体2 认证3 授权 3 SpringSecurity 基本原理4 UserDeta
  • SpringSecurity Web 权限方案

    文章目录 1 设置登录系统的账号 密码2 实现数据库认证来完成用户登录1 准备sql2 添加依赖3 编写实体类4 整合 MybatisPlus 制作 mapper5 编写登录实现类6 测试访问 3 自定义设置登录页面 xff0c 不需要认证
  • SpringSecurity 微服务对权限的整合

    文章目录 1 微服务认证与授权实现思路2 权限管理数据模型3 项目结构和功能说明3 核心业务1 代码结构图说明2 创建认证授权相关的工具类 xff08 1 xff09 DefaultPasswordEncoder xff1a 密码处理工具类
  • Idea配置热部署

    一 概念 热部署就是正在运行状态的应用 xff0c 修改了他的源码之后 xff0c 在不重新启动的情况下能够自动把增量内容编译并部署到服务器上 xff0c 使得修改立即生效 热部署为了解决的问题有两个 xff0c 一是在开发的时候 xff0
  • Vue CLI(脚手架)

    文章目录 一 Vue CLI21 Vue CLI使用前提 xff0c 需要安装NodeJS和Webpack2 Vue CLI的使用3 Vue CLI2详解4 Runtime Compiler和Runtime only的区别5 使用 npm
  • vue-router 详解

    文章目录 1 认识vue router2 安装和使用vue router3 路由的默认路径4 HTML5的History模式5 router link属性介绍6 路由代码跳转7 动态路由8 路由懒加载9 嵌套路由实现10 传递参数的方式11
  • LibTorch对tensor的索引/切片/掩码操作:对比PyTorch

    目录 一 通过索引获取值 二 通过索引设置值 三 掩码操作 在PyTorch C 43 43 API xff08 libtorch xff09 中对张量进行索引的方式与Python API的方式很相似 诸如None integer bool
  • 小米商城项目(springboot+thymeleaf)

    starsea mall 项目是一套电商系统 xff0c 包括 starsea mall 商城前台系统及商城后台系统 xff0c 基于 Spring Boot 2 X 及相关技术栈开发 前台商城系统包含首页登录 商品分类 新品上线 首页轮播
  • Idea解决SVN的代码冲突

    解决冲突 当B用户代码提交发生冲突后 xff0c 可以再次选择更新 xff1a 选择OK xff1a 弹窗如下 xff1a 如果选择Merge xff0c 则弹出版本差异的窗口 xff0c 让用户自行查看差异后再选择以哪个版本的修改为准 x
  • Axiso解决跨域访问

    首先请检查下你的 Vue 版本 xff0c Vue2 和 Vue3 跨域方式不同 xff1a vue V 2 X or 3 X 一 Vue2 版本 这里以访问 Ve2x 的一个公告API为例 xff0c 直接访问如下 xff1a span
  • SpringBoot集成Spring Security(1)——入门程序

    本篇文章环境 xff1a SpringBoot 2 0 43 Mybatis 43 Spring Security 5 0 注意 xff1a SpringSecurity 5 0 43 版本变动较多 xff0c 且不兼容之前版本 xff0c