在前面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,密码是在启动中生成的,这肯定不符合开发的需求。配置用户名密码有三种方式:

  1. 在配置文件 application.yml 中写死用户名和密码;
  2. 定义配置类,在该方法中写死用户名密码;
  3. 实现 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 | 权限管理基础的更多相关文章

  1. Spring Security(14)——权限鉴定基础

    目录 1.1     Spring Security的AOP Advice思想 1.2     AbstractSecurityInterceptor 1.2.1    ConfigAttribute ...

  2. 快速体验Spring Boot了解使用、运行和打包 | SpringBoot 2.7.2学习系列

    SpringBoot 2.7.2 学习系列,本节内容快速体验Spring Boot,带大家了解它的基本使用.运行和打包. Spring Boot 基于 Spring 框架,底层离不开 IoC.AoP ...

  3. spring security 3.1 实现权限控制

    spring security 3.1 实现权限控制 简单介绍:spring security 实现的权限控制,能够分别保护后台方法的管理,url连接訪问的控制,以及页面元素的权限控制等, secur ...

  4. 基于Spring Security2与 Ext 的权限管理设计与兑现

    基于Spring Security2与 Ext 的权限管理设计与实现 一.Spring Security介绍 Spring Security的前身Acegi,其配置及使用相对来说复杂一些,因为要配置的 ...

  5. Spring Boot集成Shrio实现权限管理

    Spring Boot集成Shrio实现权限管理   项目地址:https://gitee.com/dsxiecn/spring-boot-shiro.git   Apache Shiro是一个强大且 ...

  6. SpringBoot学习(二)—— springboot快速整合spring security组件

    Spring Security 简介 spring security的核心功能为认证(Authentication),授权(Authorization),即认证用户是否能访问该系统,和授权用户可以在系 ...

  7. Spring Security教程系列(一)基础篇-2

    第 4 章 自定义登陆页面 Spring Security虽然默认提供了一个登陆页面,但是这个页面实在太简陋了,只有在快速演示时才有可能它做系统的登陆页面,实际开发时无论是从美观还是实用性角度考虑,我 ...

  8. Spring Security教程系列(一)基础篇-1

    第 1 章 一个简单的HelloWorld 第 1 章 一个简单的HelloWorld Spring Security中可以使用Acegi-1.x时代的普通配置方式,也可以使用从2.0时代才出现的命名 ...

  9. SpringBoot集成Spring Security(6)——登录管理

    文章目录 一.自定义认证成功.失败处理 1.1 CustomAuthenticationSuccessHandler 1.2 CustomAuthenticationFailureHandler 1. ...

随机推荐

  1. JVM学习笔记-从底层了解程序运行(二)

    解决JVM运行中的问题 一个案例理解常用工具 测试代码: /** * 从数据库中读取信用数据,套用模型,并把结果进行记录和传输 */ public class T15_FullGC_Problem01 ...

  2. 2.1 动为进程,静为程序 -进程概论 -《zobolの操作系统学习札记》

    2.1 动为进程,静为程序 -进程概论 目录 2.1 动为进程,静为程序 -进程概论 问1:发明进程的原因? 问2:现在计算机中的进程的定义是什么? 问3:为什么进程跟处理器的联系更密切? 问4:进程 ...

  3. Java 泛型中的通配符

    本文内容如下: 1. 什么是类型擦除 2.常用的 ?, T, E, K, V, N的含义 3.上界通配符 < ?extends E> 4.下界通配符 < ?super E> 5 ...

  4. 【RPA之家转载】苏桦 华为RPA 企业财务实践:RPA与AI结合,实现百万级票据、合同处理自动化

    [RPA之家转载]苏桦 华为RPA 企业财务实践:RPA与AI结合,实现百万级票据.合同处理自动化 看到大会的主题,说每一位开发者都了不起,说白了我也非常的感触,因为我自己本身也是一个开发者,我从01 ...

  5. java单链表基本操作

    /** * */ package cn.com.wwh; /** * @Description:TODO * @author:wwh * @time:2021-1-18 19:24:47 */ pub ...

  6. Excel表函数自动生成SQL

    前言 在平常的工作中,多多掌握一点这样的小技巧,能够帮助我们省去很多时间: 1.数据库对应的表如下: 2.excel中需要导入的数据如下: 3.excel中sql的写法: ="insert ...

  7. .NET(C#)发送邮件的实现方法

    .NET(C#)发送邮件的实现方法 微软已经为我们准备好了现成的工具类供我们调用: MailMessage //邮件信息类 SmtpClient //邮件发送类 首先需要在项目的类文件中引用以下命名空 ...

  8. Mybatis-Generator 自定义注释

    继承DefaultCommentGenerator 或者CommentGenerator package com.zhianchen.mysqlremark.toword.config;import ...

  9. Visual Studio 生产环境配置方案:SlowCheetah

    原文 SlowCheetah 能满足你不同编译模式产生不同 app.config 配置的需求,已被微软纳入麾下,支持XML,JSON格式. 下面我们用XML的格式来试试如何使用SlowCheetah, ...

  10. 002 JWT令牌

    1.JWT数据 Json Web Token 添加数据 --> 解析数据 --> 传递数据 1.1 JWT数据处传递流程 注意:JWT数据必须携带在请求头(Request Header)的 ...