动力节点Springsecurity笔记01-05认证入门

1 问题 如何保护我们的程序?

1.1 创建code目录

目的:后面的security工程均在此目录下学习
创建code目录,并使用idea打开

1.2 不使用安全框架的springboot web程序

1.2.1 新建子模块springboot-01-hello

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uAeASGKn-1681958373972)(https://cdn.nlark.com/yuque/0/2023/png/32441366/1681955131092-bbc460d1-dc01-4b6a-bdf3-38a7a06ee7be.png#height=303&width=415)]

1.2.2 添加依赖和maven插件等

pom.xml 中部分内容如下,此处使用bootpom模板创建并粘贴

<parent>
    <artifactId>spring-boot-starter-parent</artifactId>
    <groupId>org.springframework.boot</groupId>
    <version>2.6.13</version>
    <relativePath/> <!-- lookup parent from repository -->
</parent>

<properties>
    <maven.compiler.source>8</maven.compiler.source>
    <maven.compiler.target>8</maven.compiler.target>
    <java.version>1.8</java.version>
</properties>

<dependencies>
    <!--springboot web 程序 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <!--springboot 单元测试-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
    <!--自动生成get、set和日志对象的lombok-->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
</dependencies>
<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>

1.2.3 新建启动类

com.powernode包下新建启动类Application,可以使用bootmain模板,学员自行创建

1.2.4 新建三个controller

com.powernode.controller包下新建三个controller
学生

@RestController
@RequestMapping("/student")
  public class StudentController {
    
    
    @GetMapping("/query")
    public String queryInfo(){
    
    
       return "I am a student,My name is Eric!";
    }
} 

教师

@RestController
@RequestMapping("/teacher")
  public class TeacherController {
    
    
    @GetMapping("/query")
    public String queryInfo(){
    
    
        return "I am a teacher,My name is Thomas!";
    }

} 

管理员

@RestController

@RequestMapping("/admin")

  public class AdminController {
    
    

    @GetMapping("/query")

    public String queryInfo(){
    
    

        return "I am a administrator, My name is Obama!";

    }

} 

1.2.5 启动程序

启动程序的快捷键:Ctrl+Shift+F10

1.2.6 访问程序

通过浏览器访问程序

| http://localhost:8080/student/query
http://localhost:8080/teacher/query

http://localhost:8080/admin/query

通过curl访问(可以使用git bash)

| # curl 默认发出get请求,下面可以省略 -X GET选项

curl -X GET localhost:8080/teacher/query

返回效果如下:

curl 的使用可以作为扩展学习(不讲,学员自学

| curl 是常用的命令行工具,用来请求 Web 服务器。它的名字就是命令行(Command Line)下的 URL 工具的意思。
它的功能非常强大,命令行参数多达几十种。如果熟练的话,完全可以取代 Postman 这一类的图形界面工具。

参考学习网站:
https://catonmat.net/cookbooks/curl
https://www.ruanyifeng.com/blog/2019/09/curl-reference.html
https://www.ruanyifeng.com/blog/2011/09/curl.html
https://blog.csdn.net/angle_chen123/article/details/120675472

1.2.7 结论

此示例说明:

没有加入安全框架的SpringBoot web程序,默认所有资源均不受保护。

1.2.8 问题

我们的项目很多资源必须被保护起来,如何保护?引入安全框架

2 认证授权等基本概念

2.1 认证(authentication)

2.1.1 系统为什么要认证?

认证是为了保护系统的隐私数据与资源,用户的身份合法方可访问该系统的资源。

2.1.2 什么是认证(登录)?

认证 :用户认证就是判断一个用户的身份是否合法的过程。

2.1.3 常见的用户身份认证方式

Ø 用户名密码登录
Ø 二维码登录
Ø 手机短信登录
Ø 指纹认证
Ø 人脸识别
Ø 等等…

2.2 会话(session)

2.2.1 什么是会话

用户认证通过后,为了避免用户的每次操作都进行认证可将用户的信息保存在会话中。会话就是系统为了保持当前用户的登录状态所提供的机制,常见的有基于****session方式、基于token方式等。

2.2.2 基于session的认证方式

它的交互流程是,用户认证成功后,在服务端生成用户相关的数据保存在session(当前会话)中,发给客户端的sesssion_id 存放到 cookie 中,这样用户客户端请求时带上 session_id 就可以验证服务器端是否存在 session 数据,以此完成用户的合法校验,当用户退出系统或session过期销毁时,客户端的session_id也就无效了。

2.2.3 基于token的认证方式

它的交互流程是,用户认证成功后,服务端生成一个token发给客户端,客户端可以放到 cookie 或 localStorage等存储中,每次请求时带上 token,服务端收到token通过验证后即可确认用户身份。可以使用Redis 存储用户信息(分布式中共享****session)。
基于session的认证方式由Servlet规范定制,服务端要存储session信息需要占用内存资源,客户端需要支持cookie;基于token的方式则一般不需要服务端存储token,并且不限制客户端的存储方式。如今移动互联网时代更多类型的客户端需要接入系统,系统多是采用前后端分离的架构进行实现,所以基于****token的方式更适合

2.3 授权(authorization)

2.3.1 为什么要授权(控制资源被访问)?

因为不同的用户可以访问的资源是不一样的。

2.3.2 什么是授权(给用户颁发权限)

授权: 授权是用户认证通过后,根据用户的权限来控制用户访问资源的过程。
拥有资源的访问权限则正常访问,没有权限则拒绝访问。

2.4 RBAC(Role-Based Access Control) 基于角色的访问控制

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KSusII0c-1681958373975)(https://cdn.nlark.com/yuque/0/2023/png/32441366/1681955131923-fbaab2ec-0224-43ed-bc32-7d1dcda26022.png#height=198&width=415)]
用户,角色,权限 本质:就是把权限打包给角色(角色拥有一组权限),分配给用户(用户拥有多个角色)。
最少包括五张表 (用户表、角色表、用户角色表、权限表、角色权限表)

3 java的安全框架实现

主要有三种方式:

| Ø Shiro:轻量级的安全框架,提供认证、授权、会话管理、密码管理、缓存管理等功能
Ø Spring Security:功能比Shiro强大,更复杂,权限控制细粒度更高,对OAuth2 支持更好,与Spring 框架无缝集合,使Spring Boot 集成很快捷。

Ø 自己写:基于过滤器(filter)和AOP来实现,难度大,没必要。

4 Spring Security

4.1 什么是Spring Security

Spring Security是一个能够为基于Spring的企业应用系统提供声明式(注解)的安全访问控制解决方案的安全框架。它提供了一组可以在Spring应用上下文中配置的Bean,充分利用了Spring IoC,DI(控制反转Inversion of Control ,DI:Dependency Injection 依赖注入)和AOP(面向切面编程)功能,为应用系统提供声明式的安全访问控制功能,减少了为企业系统安全控制编写大量重复代码的工作。
以上解释来源于百度百科。可以一句话来概括:

SpringSecurity 是一个安全框架

4.2 官方网址

https://spring.io/projects/spring-security

查看下官网

5 认证入门

5.1 安全入门项目

5.1.1 新建模块springsecurity-02-hello

5.1.2 添加依赖和maven插件

此处可以使用bootpom 模板创建临时文件,并拷贝。

5.1.3 添加spring-boot-starter-security依赖

|

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-security</artifactId>

5.1.4 新建启动类

新建启动类Application,学员自行创建

5.1.5 新建三个controller

参照1.2.4 创建,可以直接拷贝过来
小提示:能使用键盘的地方,多使用键盘,少使用鼠标

重命名快捷键(shift+F6),移动文件快捷键 F6

5.1.6 启动程序,并使用浏览器访问

http://localhost:8080/student/query

系统会跳转到登录页面

运行结果说明:

spring Security默认拦截了所有请求,但登录退出不拦截

5.1.7 登录系统

使用默认用户user登录系统,密码是随机生成的UUID字符串,可以在控制台(console)上找到。

登录系统,再次访问:

|http://localhost:8080/student/query
http://localhost:8080/teacher/query
http://localhost:8080/admin/query

发现登录后的用户均可以正常访问

5.1.8 退出系统

http://localhost:8080/logout


单击Log Out 按钮,成功退出

5.1.9 结论

| 引入spring-boot-starter-security依赖后,项目中除登录退出外所有资源都会被保护起来

认证(登录)用户可以访问所有资源,不经过认证用户任何资源也访问不了。

5.1.10 问题

所有资源均已保护,但是用户只用一个,密码是随机的,只能在开发环境使用

5.2 使用配置文件配置用户名和密码

5.2.1 新建模块springsecurity-03-configfile

模仿5.1.1 新建即可。

5.2.2 添加安全依赖

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

5.2.3 新建启动类

新建启动类Application,学员自行创建

5.2.4 新建三个controller

参照1.2.4 创建,可以直接拷贝过来

5.2.5 新建配置文件application.yml

添加spring security 配置信息

spring:

  security:

    user:

      name: admin

      password: 888888 

5.2.6 启动运行并使用浏览器测试

发现使用配置文件中的用户名和密码可以正常访问。
配置文件中配置用户后,默认的user用户就没有了。
示例说明:可以通过配置文件配置用户和密码,解决了使用随机生成密码的问题。

5.2.7 查看源码

问题:
Ø 查看源码的快捷键是什么?
Ø 反编译生成代码和源码的区别?
Ø 如何下载源代码?
Ø 下载后的源代码存储到哪去了?

查看源码的快捷键:ctrl+鼠标左键
application.yml 中将鼠标指定到name那,按住ctrl键,单击鼠标左键

单击上图中 Download Sources,下载源码文件

可以看到默认用户名为user,密码为使用UUID随机生成的字符串。

5.2.8 问题

Spring Security配置文件中默认配置用户是单一的用户,大部分系统都有多个用户,多个用户如何配置?

5.3 基于内存的多用户管理

5.3.1 新建模块springsecurity-04-inmemory

5.3.2 添加安全依赖

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

5.3.3 新建启动类

新建启动类Application,学员自行创建

5.3.4 新建三个controller

参照1.2.4 创建,可以直接拷贝过来

5.3.5 新建配置文件application.yml

参照5.2.5 ,可以直接拷贝内容

5.3.6 新建配置类


com.powernode.config包下新建配置类MySecurityUserConfig,如下:

@Configuration
  public class MySecurityUserConfig {
    
    
     @Bean
    public UserDetailsService userDetailService() {
    
    
  //        使用org.springframework.security.core.userdetails.User类来定义用户
        //定义两个用户
        UserDetails user1 = User._builder_().username("eric").password("123456").roles("student").build();
        UserDetails user2 = User._builder_().username("thomas").password("123456").roles("teacher").build();
        //创建两个用户
        InMemoryUserDetailsManager userDetailsManager = new InMemoryUserDetailsManager();
        userDetailsManager.createUser(user1);
        userDetailsManager.createUser(user2);
        return userDetailsManager;
      }
  
} 

5.3.7 启动程序测试

登录页面输入用户名(thomas)和密码(123456),然后单击登录后,控制台报错,如下:

报错的原因如下:
这个是因为spring Sercurity强制要使用密码加密,当然我们也可以不加密,但是官方要求是不管你是否加密,都必须配置一个密码编码(加密)器

5.3.8 添加密码加密器bean但是不对密码加密

在MySecurityUserConfig类中加入以下bean

 /*
 *从 Spring5 开始,强制要求密码要加密
 *如果非不想加密,可以使用一个过期的 PasswordEncoder 的实例 NoOpPasswordEncoder,
 *但是不建议这么做,毕竟不安全。
 
 *@return
 */
  @Bean
  public PasswordEncoder passwordEncoder(){
    
    
    //不对密码进行加密,使用明文
    return NoOpPasswordEncoder._getInstance_();
  } 

重启程序再次使用thomas/123456登录测试,可以登录正常访问了。
使用admin/888888登录,登录不成功,说明:我们只要添加了安全配置类,那么我们在****yml里面的配置就失效了

此处可以查看一下NoOpPasswordEncoder源码,再看一下单例模式,加密和密码对比方法
英文小提示:
明文:plaintext
密文:ciphertext
问题:
Ø 密码为什么要加密?加密的方式有哪些? 涉及到密码加密问题
Ø NoOpPasswordEncoder此类已经过期,而且还没有加密,如何解决?下章解决
Ø 以学生身份登录,发现不但可以访问学生的页面,还可以访问教师的页面和管理员的页面,如何解决? 权限问题,后面解决
Ø 如果要动态的创建用户,或者修改密码等(不是把用户名和密码写死到代码中),怎么办? 认证信息要存储到数据库中。

下面一章讲解密码加密问题

猜你喜欢

转载自blog.csdn.net/f5465245/article/details/130261010
今日推荐