01 - 快速体验 Spring Security 5.7.2 | 权限管理基础
在前面SpringBoot 2.7.2 的系列文章中,已经创建了几个 computer 相关的接口,这些接口直接通过 Spring Doc 或 POSTMAN 就可以访问。例如:
GET http://localhost:9099/computer/1
访问该服务可以获取 id 为 1 的电脑详情。
接下来的文章就使用 Spring Security 实现用户认证和授权。
1 添加 Spring Security
1.1 添加依赖
Spring Boot 对 Spring Security 非常友好,它已经管理了 Spring Security 的依赖版本,并且提供 starter 的方式进行整合:
<!-- Spring Security -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
1.2 测试服务
添加依赖后重新启动服务,可以在控制台看到输出:

在浏览器中访问该服务,会自动跳转到登录页面,该页面是 Spring Security 默认提供的。浏览器中地址栏自动跳转到:
http://localhost:9099/login。
在登录页面,用户名填写 user,密码填写上面控制台中输出的密码,点击“Sign in”,便会进入系统,显示电脑详情。
2 硬编码配置用户名和密码
咱们使用的 Spring Boot 版本是 2.7.2,对应的 Spring Security 版本为 5.7.2,从 5.7 开始,Spring Security 的使用有一些改变,其中之一就是配置 Security 时不推荐继承 WebSecurityConfigurerAdapter 类。
上面的 demo 中使用的用户名是 user,密码是在启动中生成的,这肯定不符合开发的需求。配置用户名密码有三种方式:
- 在配置文件 application.yml 中写死用户名和密码;
- 定义配置类,在该方法中写死用户名密码;
- 实现 UserDetailsService 接口,然后定义配置类进行配置。
前面两者在 demo 中玩玩就行。
2.1 在配置文件中配置用户名密码
这种方式比较简单,直接在 application.yml 中配置即可:
spring:
profiles:
active: @env@
security:
user:
name: hero1
password: '111111'
roles: 'admin'
2.2 在内存中配置用户名密码
删除上面的 security 节点相关的配置,使用配置文件,配置在内存中生效的用户名密码。
创建配置类 SecurityConfig:
package com.yygnb.demo.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
@Configuration
public class SecurityConfig {
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public InMemoryUserDetailsManager userDetailsService() {
UserDetails user = User.builder()
.username("hero2")
.password(passwordEncoder().encode("111111"))
.roles("admin")
.build();
return new InMemoryUserDetailsManager(user);
}
}
重启服务,登录界面输入 hero2/111111 进行测试。
这种方式也是写死的用户名密码,在实际开发中不会使用的。所以,先删除这个文件,然后再继续后面的学习。
3 数据库配置用户名和密码
在开始这个部分之前,请确保删除了上面编写的 SecurityConfig。
3.1 数据库表
首先需要定义表结构。
由于我这里是基于前面 spring boot 2.7.2 系列文章的demo进行的,我继续沿用 Liquibase 的方式定义表结构。尊敬的读者们可以从 GitHub 上获取 demo 基础工程,也可以联系我获取,还可以脱离 demo 基础工程,自己用习惯的方式创建数据库表结构,如 SQL 语句、图形化界面等。
在 resources/db/demo/ 目录中创建文件 demo-changelog-v2.xml,该文件用来定义这次数据库的变更。
<?xml version="1.0" encoding="UTF-8"?>
<databaseChangeLog xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
https://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.1.xsd">
<changeSet id="T100-20220801-yyg-025" author="yyg">
<createTable remarks="用户表" tableName="user">
<column autoIncrement="true" name="id" type="BIGINT">
<constraints nullable="false" primaryKey="true"/>
</column>
<column name="username" remarks="用户名" type="VARCHAR(32)">
<constraints nullable="false"/>
</column>
<column name="password" remarks="密码" type="VARCHAR(128)">
<constraints nullable="false"/>
</column>
<column name="name" remarks="姓名" type="VARCHAR(32)">
<constraints nullable="false"/>
</column>
</createTable>
<addAutoIncrement tableName="user" columnName="id" columnDataType="BIGINT"
incrementBy="1" startWith="1"/>
<insert tableName="user">
<column name="id" valueNumeric="1"/>
<column name="username" value="hero1"/>
<column name="password" value="111111"/>
<column name="name" value="HERO 1"/>
</insert>
<insert tableName="user">
<column name="id" valueNumeric="2"/>
<column name="username" value="hero2"/>
<column name="password" value="222222"/>
<column name="name" value="HERO 2"/>
</insert>
<insert tableName="user">
<column name="id" valueNumeric="3"/>
<column name="username" value="hero3"/>
<column name="password" value="333333"/>
<column name="name" value="HERO 3"/>
</insert>
</changeSet>
</databaseChangeLog>
该文件定义了 user 表并插入了三条数据,user 表只有四个字段:id 主键、用户名、密码、姓名,主键自增长。
重启服务,会自动生成表结构。
3.2 生成实体类
可以通过逆向工程生成,可以复制下面的代码。
com.yygnb.demo.entity.User
/**
* 用户表
*/
@Schema(title = "用户")
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class User implements Serializable {
private static final long serialVersionUID = 1L;
@TableId(value = "id", type = IdType.AUTO)
private Long id;
@Schema(title = "用户名")
@NotNull(message = "不能为空")
private String username;
@Schema(title = "密码")
@NotNull(message = "不能为空")
private String password;
@Schema(title = "姓名")
private String name;
}
3.3 Mapper
com.yygnb.demo.mapper.UserMapper:
public interface UserMapper extends BaseMapper<User> {
}
resources/mapper/UserMapper.xml:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.yygnb.demo.mapper.UserMapper">
</mapper>
到这一步,准备工作就完成了,接下来继续回到 Spring Security。
3.4 PasswordEncoder
Spring Security 中在认证授权时,需要 PasswordEncoder 对象,该对象可以对密码加密。
com.yygnb.demo.config.PasswordEncoderConfig:
@Configuration
public class PasswordEncoderConfig {
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
3.5 实现 UserDetailsService 接口
Spring Security 提供了一个接口:UserDetailsService 。该接口只有一个方法 loadUserByUsername,在该方法中就可以查询数据库,根据用户名查询用户信息了。该方法返回 UserDetails。UserDetails 是一个接口,Spring Security 提供了一个实现类 User。
创建类:UserDetailsServiceImpl,实现 UserDetailsService 接口,并添加 @Service 注解。
com.yygnb.demo.service.impl.UserDetailsServiceImpl:
package com.yygnb.demo.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.yygnb.demo.entity.User;
import com.yygnb.demo.mapper.UserMapper;
import lombok.RequiredArgsConstructor;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import java.util.List;
@RequiredArgsConstructor
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
// @Autowired
private final PasswordEncoder passwordEncoder;
private final UserMapper userMapper;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.eq("username", username);
User user = this.userMapper.selectOne(wrapper);
if (user == null) {
throw new UsernameNotFoundException("根据用户名未查询到用户");
}
// 模拟查询权限
List<GrantedAuthority> authorities = AuthorityUtils.commaSeparatedStringToAuthorityList("admin");
return new org.springframework.security.core.userdetails.User(
user.getUsername(), passwordEncoder.encode(user.getPassword()), authorities);
}
}
如果是以前版本的 Spring Security,还需要定义配置继承自 WebSecurityConfigurerAdapter 类,重写 config 方法,并在该方法中设置 UserDetailsService 等。现在的版本不需要这些无聊的操作了。
重启服务,访问测试。
感谢你阅读本文,如果本文给了你一点点帮助或者启发,还请三连支持一下,点赞、关注、收藏,作者会持续与大家分享更多干货
01 - 快速体验 Spring Security 5.7.2 | 权限管理基础的更多相关文章
- Spring Security(14)——权限鉴定基础
目录 1.1 Spring Security的AOP Advice思想 1.2 AbstractSecurityInterceptor 1.2.1 ConfigAttribute ...
- 快速体验Spring Boot了解使用、运行和打包 | SpringBoot 2.7.2学习系列
SpringBoot 2.7.2 学习系列,本节内容快速体验Spring Boot,带大家了解它的基本使用.运行和打包. Spring Boot 基于 Spring 框架,底层离不开 IoC.AoP ...
- spring security 3.1 实现权限控制
spring security 3.1 实现权限控制 简单介绍:spring security 实现的权限控制,能够分别保护后台方法的管理,url连接訪问的控制,以及页面元素的权限控制等, secur ...
- 基于Spring Security2与 Ext 的权限管理设计与兑现
基于Spring Security2与 Ext 的权限管理设计与实现 一.Spring Security介绍 Spring Security的前身Acegi,其配置及使用相对来说复杂一些,因为要配置的 ...
- Spring Boot集成Shrio实现权限管理
Spring Boot集成Shrio实现权限管理 项目地址:https://gitee.com/dsxiecn/spring-boot-shiro.git Apache Shiro是一个强大且 ...
- SpringBoot学习(二)—— springboot快速整合spring security组件
Spring Security 简介 spring security的核心功能为认证(Authentication),授权(Authorization),即认证用户是否能访问该系统,和授权用户可以在系 ...
- Spring Security教程系列(一)基础篇-2
第 4 章 自定义登陆页面 Spring Security虽然默认提供了一个登陆页面,但是这个页面实在太简陋了,只有在快速演示时才有可能它做系统的登陆页面,实际开发时无论是从美观还是实用性角度考虑,我 ...
- Spring Security教程系列(一)基础篇-1
第 1 章 一个简单的HelloWorld 第 1 章 一个简单的HelloWorld Spring Security中可以使用Acegi-1.x时代的普通配置方式,也可以使用从2.0时代才出现的命名 ...
- SpringBoot集成Spring Security(6)——登录管理
文章目录 一.自定义认证成功.失败处理 1.1 CustomAuthenticationSuccessHandler 1.2 CustomAuthenticationFailureHandler 1. ...
随机推荐
- 掘地三尺搞定 Redis 与 MySQL 数据一致性问题
Redis 拥有高性能的数据读写功能,被我们广泛用在缓存场景,一是能提高业务系统的性能,二是为数据库抵挡了高并发的流量请求,点我 -> 解密 Redis 为什么这么快的秘密. 把 Redis 作 ...
- 有关安装pycocotools的办法
1,首先需要安装Visual C++ 2015构建工具,地址https://download.microsoft.com/download/5/f/7/5f7acaeb-8363-451f-9425- ...
- 《ECMAScript 6 入门》【三、字符串的扩展】(持续更新中……)
前言: 本篇介绍 ES6 对字符串的改造和增强.一.字符的 Unicode 表示法 字符的 Unicode 码点必须在\u0000~\uFFFF之间,\uxxxx形式表示一个字符,其中xxxx表示字符 ...
- 前端下载图片的N种方法
前几天一个简单的下载图片的需求折腾了我后端大佬好几天,最终还是需要前端来搞,开始说不行的笔者最后又行了,所以趁着这个机会来总结一下下载图片到底有多少种方法. 先起个服务 使用expressjs起个简单 ...
- C#生成putty格式的ppk文件(支持passphrase)
背景 2022国家级护网行动即将开启,根据阿里云给出的安全建议,需要将登陆Linux的方式改为密钥对方式.我这里使用的远程工具是自己开发的,能够同时管理Windows和Linux,但是以前不支持密钥对 ...
- Spring框架系列(12) - Spring AOP实现原理详解之JDK代理实现
上文我们学习了SpringAOP Cglib动态代理的实现,本文主要是SpringAOP JDK动态代理的案例和实现部分.@pdai Spring框架系列(12) - Spring AOP实现原理详解 ...
- CentOS7系统DNS主从配置
CentOS7系统DNS主从配置:一.DNS服务器正向解析:1.1 基础环境:主机IP 主机名 操作系统 用途192.168.0.110 master ...
- intellidea 快捷键-*01
快捷键: 0.竖向选择文本: alt+shift+insert:https://www.cnblogs.com/JonaLin/p/11422110.html 如果想修改快捷键(setting-> ...
- RK3568开发笔记(四):在虚拟机上使用SDK编译制作uboot、kernel和buildroot镜像
前言 上一篇搭建好了ubuntu宿主机开发环境,本篇的目标系统主要是开发linux+qt,所以需要刷上billdroot+Qt创建的系统,为了更好的熟悉原理和整个开发过程,选择从零开始搭建rk35 ...
- ShardingSphere数据库读写分离
码农在囧途 最近这段时间来经历了太多东西,无论是个人的压力还是个人和团队失误所带来的损失,都太多,被骂了很多,也被检讨,甚至一些不方便说的东西都经历了,不过还好,一切都得到了解决,无论好坏,这对于个人 ...