1-快速体验 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 的方式进行整合:


    org.springframework.boot
    spring-boot-starter-security

1.2 测试服务

添加依赖后重新启动服务,可以在控制台看到输出:

1-快速体验 Spring Security 5.7.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,该文件用来定义这次数据库的变更。


该文件定义了 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 {
}

resources/mapper/UserMapper.xml


到这一步,准备工作就完成了,接下来继续回到 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 wrapper = new QueryWrapper<>();
        wrapper.eq("username", username);
        User user = this.userMapper.selectOne(wrapper);
        if (user == null) {
            throw new UsernameNotFoundException("根据用户名未查询到用户");
        }

        // 模拟查询权限
        List authorities = AuthorityUtils.commaSeparatedStringToAuthorityList("admin");
        return new org.springframework.security.core.userdetails.User(
                user.getUsername(), passwordEncoder.encode(user.getPassword()), authorities);
    }
}

如果是以前版本的 Spring Security,还需要定义配置继承自 WebSecurityConfigurerAdapter 类,重写 config 方法,并在该方法中设置 UserDetailsService 等。现在的版本不需要这些无聊的操作了。

重启服务,访问测试。

感谢你阅读本文,如果本文给了你一点点帮助或者启发,还请三连支持一下,点赞、关注、收藏,作者会持续与大家分享更多干货

Original: https://www.cnblogs.com/youyacoder/p/16636121.html
Author: 程序员优雅哥(/同)
Title: 1-快速体验 Spring Security 5.7.2 | 权限管理基础

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/619809/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • roketmq安装和运行

    软件下载: 链接:https://pan.baidu.com/s/1CRFQyQrVsKQHFTkU5m3-Hg提取码:gejx复制这段内容后打开百度网盘手机App,操作更方便哦 …

    Java 2023年5月30日
    076
  • Java全家桶的这些知识,不用学了

    众所周知,Java 的知识体系繁冗复杂,但是有很多知识在实际工作中几乎没有人用。 很多人在学习过程中,却经常把有限的时间和精力花在了这些” 没有用“的知识上…

    Java 2023年6月7日
    065
  • Java 及 Kotlin 中的可变参数 vararg

    本文地址 目录 目录 Java 及 Kotlin 中的可变参数 vararg Java 中可变参数的规则 可变参数的本质是数组 Java 中对应数组 T[] Kotlin 中可能对…

    Java 2023年5月29日
    097
  • nginx防止浏览器自动打开下载的文件

    add_header Content-Disposition "attachment;"; 举例:#所有文件都不打开 location / { add_head…

    Java 2023年5月30日
    078
  • 调用第三方API的方法HttpClient

    Java调用API很简单,主要分为三步: ①找到要调用的API接口 ②向指定URL添加参数发送请求 ③对返回的字符串进行处理 java调用API的方式: HttpClient 是A…

    Java 2023年5月29日
    085
  • NoteOfMySQL-10-触发器与事件

    触发器是由事件来触发某个操作,这些事件包括insert语句、update语句、delete语句,当数据库系统执行这些事件时,就会激活触发器执行相应的操作。事件调度器(event s…

    Java 2023年6月5日
    082
  • Spring Boot整合Swagger报错:”this.condition” is null

    前段时间看到群里有吐槽swagger整合问题,当时没仔细看,总以为是姿势不对。 这两天正好自己升级Spring Boot版本,然后突然出现了这样的一个错误: Caused by: …

    Java 2023年6月9日
    094
  • 4、自定义菜单

    1、自定义菜单最多包括3个一级菜单,每个一级菜单最多包含5个二级菜单。2、一级菜单最多4个汉字,二级菜单最多7个汉字,多出来的部分将会以”…”代…

    Java 2023年6月13日
    068
  • Java异常机制

    什么是异常 实际工作中,遇到的情况不可能是非常完美的。比如:你写的某个模块,用户输入不一定符合你的要求;你的程序要打开某个文件,这个文件可能不存在或者文件格式不对;你要读取数据库的…

    Java 2023年6月5日
    086
  • JavaScript基础知识

    undefined window.alert() –写入警告框 document.write()—写入HTML输出 console.log()—写入浏览器控制台 aler…

    Java 2023年6月5日
    081
  • 静态代理、动态代理与Mybatis的理解

    静态代理、动态代理与Mybatis的理解 这里的 代理与设计模式中的代理模式密切相关,代理模式的主要作用是为其他对象提供一种控制对这个对象的访问方法,即在一个对象不适合或者不能直接…

    Java 2023年6月8日
    078
  • Kubernetes 存储概念之Volumes介绍

    默认情况下容器中的磁盘文件是非持久化的,对于运行在容器中的应用来说面临两个问题,第一:当容器挂掉,K8S重启它时,文件将会丢失;第二:当 Pod中同时运行多个容器,容器之间需要共享…

    Java 2023年6月16日
    089
  • Spring Boot + Spring Cloud 实现权限管理系统 后端篇(二十四):权限控制(Shiro 注解)

    在线演示 用户名:admin 密码:admin 技术背景 当前,我们基于导航菜单的显示和操作按钮的禁用状态,实现了页面可见性和操作可用性的权限验证,或者叫访问控制。但这仅限于页面的…

    Java 2023年5月30日
    097
  • Hexo 必装插件

    可以优化博客路径,默认路径 https://xcmaster.com/2022/07/07/hexo&#x5FC5;&#x88C5;&#x63D2;&amp…

    Java 2023年6月9日
    071
  • 你不知道的PageContext

    你不知道的PageContext 最近在文艺复兴,学习JSP和Servlet,此文为笔者学习记录。 本文分为以下几个部分: 前言 环境搭建 正文 总结 前言 在我们使用的项目中,存…

    Java 2023年6月5日
    090
  • 【一知半解】synchronied

    synchronized是什么 synchronized是java同步锁,同一时刻多个线程对同一资源进行修改时,能够保证同一时刻只有一个线程获取到资源并对其进行修改,因此保证了线程…

    Java 2023年6月9日
    072
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球