简介
在权限管理框架中,往往离不开认证 (authentication),授权(authorization) 这两个概念,这两个单词"很像",表示的意思却大相径庭。
-
认证:对用户信息进行身份认证 (Who are you? 你是谁?)
-
授权:给认证过的用户赋予访问资源的权限 (What can you do?你可以做什么?)
本文浅析的java权限管理框架 spring security 也是围绕这两个概念展开的,它依托于同spring生态良好配合,完整全面的功能模块,收获了一大批开发人员的青睐。
最简单的应用
为了方便代码的调试,我们借助spring boot搭建一个简单的权限管理项目。
首先,我们使用maven来管理包引用,pom.xml 文件内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<name>security演示项目</name>
<groupId>xin.sunce</groupId>
<artifactId>spring-boot-security</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>jar</packaging>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.4.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
</dependencies>
</project>
创建启动类并开发一个简单的Rest接口
@EnableWebMvc
@RestController
@SpringBootApplication
public class Application {
@GetMapping("/home")
public String home() {
return "hello world";
}
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
执行Application#main启动应用,由于我们没有做任何的配置,security会使用默认的用户名: user,并生成默认的密码,输出在启动日志中;例如
Using generated security password: dacbfd04-716c-4be2-bba2-f40a2d9ea454
也可以在配置文件中指定用户名密码,配置如下:
spring.security.user.name=root
spring.security.user.password=123456
启动应用后,访问地址 http://127.0.0.1:8080/home 会默认跳转到security默认的登录页面;至此,我们可以一起开启快乐的debug之旅了。
security 概述
假如,你的开发负责人需要你编码一个权限管理的功能;你会如何来实现呢?
很多朋友可能会想到通过 AOP,Filter来实现,而security 正是通过 Filter 来实现的。
当初始化spring security时,会创建一个 FilterChainProxy 的过滤器,它是javax.servlet.Filter 子类,因此所有的请求都会经过它。FilterChainProxy 是一个代理类,真正发挥作用的是FilterChainProxy中SecurityFilterChain的各个Filter,而这些Filter也正式security的核心。
基本处理流程如下:
我们之前说过权限管理的两大核心:认证,授权;这些Filter很重要,但是它们并不直接参与认证,授权;其中认证环节是通过 AuthenticationManager 来完成的,而授权环节是通过AccessDecisionManager 完成的。
认证流程
采用security简单示例的认证成功时序图如下:
-
UsernamePasswordAuthenticationFilter拦截到登录信息,并将其封装成UsernamePasswordAuthenticationToken,随后尝试认证,
-
调用 AuthenticationManager的子类ProviderManager#authenticate方法
- DaoAuthenticationProvider是AuthenticationManager的子类调用 UserDetailsService#loadUserByUsername 获取UserDetails 信息
- 获取到UserDetails信息后与请求的User信息做密码匹配校验,校验通过后填充相关权限信息
- 返回认证过的UsernamePasswordAuthenticationToken (Authentication 子类)
- 将认证成功的 Authentication 放置到 SecurityContextHolder.getContext() 的上下文中
至此整个认证流程告一段落。
授权流程
同样的授权流程也是通过Filter实现的,我们先看一下时序图,如下:
- 认证成功后访问受保护资源,会调用FilterSecurityInterceptor会在doFilter方法中调用invoke()
- 调用父类AbstractSecurityInterceptor#beforeInvocation
- 从SecurityMetadataSource#getAttributes获取可访问资源
- 通过accessDecisionManager#decide 觉得资源是否放行
- 其实现类中通过 AccessDecisionVoter 来投票是否放行
以上便是授权的基本流程。
作者在研读源码的过程中受到 CSDN 博主 借汝之光,得以光明颇多启发 ,https://blog.csdn.net/weixin_44588495/article/details/105907312;万分感谢。
参考资料:
CSDN:
https://blog.csdn.net/weixin_44588495/article/details/105907312
知乎:
https://zhuanlan.zhihu.com/p/100014456
作者是一个技术肥宅,还在不断的学习进步中,十分欢迎各位 杠精 读者指出文中不足之处,欢迎您来留言提问;也欢迎转载,烦请注明出处。
- 本文链接: https://www.sunce.wang/archives/springsecurity原理浅析
- 版权声明: 本博客所有文章除特别声明外,均采用CC BY-NC-SA 3.0 许可协议。转载请注明出处!