SpringSecurity

1、学习目标

image-20201230205324121.png

2、SpringSecurity简介

2.1 安全框架的概述

什么是安全框架?解决系统安全问题的框架,如果没有安全框架,我们就需要手动处理每个资源的访问控制,非常麻烦。使用安全框架,我们可以通过配置的方法实现对资源的访问控制。

2.1.2 常用安全框架

1、Spring Security:Spring家族一员。是一个能偶为基于Spring的企业级应用系统提供声明式的安全访问控制解决方案的安全框架。它提供了一组可以在Spring应用上下文中配置的Bean,充分利用了Spring Ioc(控制反转Inversion of Control,ID:Dependency Injection)依赖注入AOP(面向切面编程)功能,为应用系统提供声明式安全访问控制功能,减少了企业系统安全控制编写大量重复代码工作。 2、Apache Shiro:一个功能强大且易于使用的java安全框架,提供了认证,授权,加密和会话管理。

Spring Security简介

概述

Spring Security是一个高度自定义的安全框架。利用 Spring IoC/DI和AOP功能,为系统提供了声明 式安全访问控制功能,减少了为系统安全而编写大量重复代码的工作。使用 Spring Secruity 的原因有 很多,但大部分都是发现了 javaEE的 Servlet 规范或 EJB 规范中的安全功能缺乏典型企业应用场景。同 时认识到他们在 WAR 或 EAR 级别无法移植。因此如果你更换服务器环境,还有大量工作去重新配置你 的应用程序。使用 Spring Security解决了这些问题,也为你提供许多其他有用的、可定制的安全功能。 正如你可能知道的两个应用程序的两个主要区域是“认证”和“授权”(或者访问控制)。这两点也是 Spring Security 重要核心功能。“认证”,是建立一个他声明的主体的过程(一个“主体”一般是指用户, 设备或一些可以在你的应用程序中执行动作的其他系统),通俗点说就是系统认为用户是否能登录。 “授权”指确定一个主体是否允许在你的应用程序执行一个动作的过程。通俗点讲就是系统判断用户是否 有权限去做某些事情。

历史

Spring Security 以“The Acegi Secutity System for Spring”的名字始于2003年年底。其前身为 acegi 项目。起因是 Spring 开发者邮件列表中一个问题,有人提问是否考虑提供一个基于 Spring 的安全实 现。限制于时间问题,开发出了一个简单的安全实现,但是并没有深入研究。几周后,Spring 社区中其 他成员同样询问了安全问题,代码提供给了这些人。2004 年 1 月份已经有 20 人左右使用这个项目。随 着更多人的加入,在 2004 年 3 月左右在 sourceforge 中建立了一个项目。在最开始并没有认证模块, 所有的认证功能都是依赖容器完成的,而 acegi 则注重授权。但是随着更多人的使用,基于容器的认证 就显现出了不足。acegi 中也加入了认证功能。大约 1 年后 acegi 成为 Spring子项目。在 2006 年 5 月 发布了 acegi 1.0.0 版本。2007 年底 acegi 更名为Spring Security。

快速入门

导入依赖

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
  5. https://maven.apache.org/xsd/maven-4.0.0.xsd">
  6. <modelVersion>4.0.0</modelVersion>
  7. <parent>
  8. <groupId>org.springframework.boot</groupId>
  9. <artifactId>spring-boot-starter-parent</artifactId>
  10. <version>2.2.2.RELEASE</version>
  11. <relativePath/> <!-- lookup parent from repository -->
  12. </parent>
  13. <groupId>com.xxxx</groupId>
  14. <artifactId>springsecurity-demo</artifactId>
  15. <version>0.0.1-SNAPSHOT</version>
  16. <name>springsecurity-demo</name>
  17. <description>Demo project for Spring Boot</description>
  18. <properties>
  19. <java.version>1.8</java.version>
  20. </properties>
  21. <dependencies>
  22. <!--spring security 组件-->
  23. <dependency>
  24. <groupId>org.springframework.boot</groupId>
  25. <artifactId>spring-boot-starter-security</artifactId>
  26. </dependency>
  27. <!--web 组件-->
  28. <dependency>
  29. <groupId>org.springframework.boot</groupId>
  30. <artifactId>spring-boot-starter-web</artifactId>
  31. </dependency>
  32. <!-- test 组件-->
  33. <dependency>
  34. <groupId>org.springframework.boot</groupId>
  35. <artifactId>spring-boot-starter-test</artifactId>
  36. <scope>test</scope>
  37. <exclusions>
  38. <exclusion>
  39. <groupId>org.junit.vintage</groupId>
  40. <artifactId>junit-vintage-engine</artifactId>
  41. </exclusion>
  42. </exclusions>
  43. </dependency>
  44. <dependency>
  45. <groupId>org.springframework.security</groupId>
  46. <artifactId>spring-security-test</artifactId>
  47. <scope>test</scope>
  48. </dependency>
  49. </dependencies>
  50. <build>
  51. <plugins>
  52. <plugin>
  53. <groupId>org.springframework.boot</groupId>
  54. <artifactId>spring-boot-maven-plugin</artifactId>
  55. </plugin>
  56. </plugins>
  57. </build>
  58. </project>

前端页面

login.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
</head>
<body>
<form action="/login" method="post">
 用户名:<input type="text" name="username" /><br/>
 密码:<input type="password" name="password" /><br/>
  <input type="submit" value="登录" />
</form>
</body>
</html>

访问页面

导入spring-boot-starter-security 启动器后,Spring Security 已经生效,默认拦截全部请求,如果用 户没有登录,跳转到内置登录页面

image-20201231153617229.png

默认的 username 为 user,password 打印在控制台中。 在浏览器中输入账号和密码后会显示 login.html 页面内容。

UserDetailsService详解

当什么也没有配置的时候,账号和密码是由 Spring Security 定义生成的。而在实际项目中账号和密 码都是从数据库中查询出来的。所以我们要通过自定义逻辑控制认证逻辑。如果需要自定义逻辑时,只 需要实现 UserDetailsService 接口即可。接口定义如下:

public interface UserDetailsService {
    UserDetails loadUserByUsername(String var1) throws UsernameNotFoundException;
}

返回值

返回值 UserDetails 是一个接口,定义如下

public interface UserDetails extends Serializable {
    //获取所有权限
    Collection<? extends GrantedAuthority> getAuthorities();
    //获取密码
    String getPassword();
    //获取用户名
    String getUsername();
    //是否账号过期
    boolean isAccountNonExpired();
    //是否账号被锁定
    boolean isAccountNonLocked();
    //凭证(密码)是否过期
    boolean isCredentialsNonExpired();
    //是否可用
    boolean isEnabled();
}

UserDetails 的实例就只能返回接口的实现类。SpringSecurity 中提供了如下的实例。对于 我们只需要使用里面的 User 类即可。注意 User 的全限定路径是: org.springframework.security.core.userdetails.User 此处经常和系统中自己开发的 User 类弄 混。

image-20201231154005249.png

image-20201231154100216.png

其中构造方法有两个,调用其中任何一个都可以实例化 UserDetails 实现类 User 类的实例。而三个参数的构造方法实际上也是调用 7 个参数的构造方法。

  • username :用户名
  • password :密码
  • authorities :用户具有的权限。此处不允许为 null

image-20201231154221461.png

此处的用户名应该是客户端传递过来的用户名。而密码应该是从数据库中查询出来的密码。Spring Security 会根据 User 中的 password 和客户端传递过来的 password 进行比较。如果相同则表示认证 通过,如果不相同表示认证失败。