Skip to content

Commit 401f61b

Browse files
authored
feat:update docs (#73)
1 parent 00a53ce commit 401f61b

File tree

9 files changed

+231
-4
lines changed

9 files changed

+231
-4
lines changed
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# Databasir 登录授权流程
2+
3+
### [一、用户名密码登录认证流程](README/develop/login-and-auth/username-and-password/index.md)
4+
5+
### [二、OAuth2 登录认证流程](README/develop/login-and-auth/oauth2/index.md)
6+
7+
8+
9+
20.6 KB
Loading
79.5 KB
Loading
69.8 KB
Loading
Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
# 用户名密码登录解析
2+
3+
## 相关代码位置
4+
5+
相关代码都位于 `API` 模块下的
6+
7+
- 【package】com.databasir.api.config.security.*
8+
- 【class】com.databasir.api.config.SecurityConfig.java
9+
10+
11+
12+
## 登录认证过滤器
13+
14+
Databasir 的登录认证都是在 Filter 中实现的,目前有两个自定义的 Filter
15+
16+
- `DatabasirOauth2LoginFilter`:负责处理 OAuth2 登录的请求
17+
- `DatabasirJwtTokenFilter`:负责验证登录凭证的有效性
18+
19+
用户名和密码的登录采用 Spring Security 自带的 Filter
20+
21+
- `UsernamePasswordAuthenticationFilter`:负责处理用户名密码登录的请求
22+
23+
用户登录请求都会经过这三个过滤器
24+
25+
![](img/1-filter.png)
26+
27+
由于本篇主要说明用户明密码登录这一流程,所以会重点专注于 `UsernamePasswordFilter` 这一过滤器。
28+
29+
## 登录认证相关类
30+
31+
用户名密码登录是基于 Spring Security 提供的 `UsernamePasswordAuthenticationFilter` 实现。
32+
33+
Databasir 根据该过滤器的扩展点自定义了以下类
34+
35+
- DatabasirAuthenticationFailureHandler:登录失败回调
36+
- DatabasirAuthenticationSuccessHandler:登录成功回调
37+
- DatabasirUserDetailService:获取用户登录信息的 service
38+
- DatabasirUserDetails:用户的登录信息(扩展了角色信息)
39+
40+
这些类的装配都在 `com.databasir.api.config.SecurityConfig.java` 中,下面展示了一部分源码,重点关注 `configure(HttpSecurity)` 方法
41+
42+
```java
43+
@Configuration
44+
@RequiredArgsConstructor
45+
@EnableGlobalMethodSecurity(prePostEnabled = true)
46+
public class SecurityConfig extends WebSecurityConfigurerAdapter {
47+
48+
private final DatabasirUserDetailService databasirUserDetailService;
49+
50+
private final DatabasirAuthenticationEntryPoint databasirAuthenticationEntryPoint;
51+
52+
private final DatabasirJwtTokenFilter databasirJwtTokenFilter;
53+
54+
private final DatabasirAuthenticationFailureHandler databasirAuthenticationFailureHandler;
55+
56+
private final DatabasirAuthenticationSuccessHandler databasirAuthenticationSuccessHandler;
57+
58+
@Override
59+
protected void configure(HttpSecurity http) throws Exception {
60+
http.headers().frameOptions().disable();
61+
http.csrf().disable();
62+
http.cors();
63+
64+
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
65+
.and()
66+
// 启用 form 表单登录方式,配置登录地址为 /login,并制定成功和失败的回调处理类
67+
.formLogin()
68+
.loginProcessingUrl("/login")
69+
.failureHandler(databasirAuthenticationFailureHandler)
70+
.successHandler(databasirAuthenticationSuccessHandler)
71+
.and()
72+
.authorizeRequests()
73+
// 登录和 Token 刷新无需授权
74+
.antMatchers("/login", Routes.Login.REFRESH_ACCESS_TOKEN)
75+
.permitAll()
76+
// oauth 回调地址无需鉴权
77+
.antMatchers("/oauth2/apps", "/oauth2/authorization/*", "/oauth2/login/*")
78+
.permitAll()
79+
// 静态资源无需鉴权
80+
.antMatchers("/", "/*.html", "/js/**", "/css/**", "/img/**", "/*.ico")
81+
.permitAll()
82+
// api 请求需要授权
83+
.antMatchers("/api/**").authenticated()
84+
.and()
85+
.exceptionHandling()
86+
.authenticationEntryPoint(databasirAuthenticationEntryPoint);
87+
88+
http.addFilterBefore(
89+
databasirJwtTokenFilter,
90+
UsernamePasswordAuthenticationFilter.class
91+
);
92+
}
93+
94+
@Override
95+
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
96+
// 这里指定了 userDetailService 为自定义的 DatabasirUserDetailService
97+
auth.userDetailsService(databasirUserDetailService)
98+
.passwordEncoder(bCryptPasswordEncoder());
99+
}
100+
101+
}
102+
```
103+
104+
105+
106+
## 登录认证过滤器处理流程
107+
108+
当请求经过 `UsernamePasswordAuthenticationFilter` 时,该过滤器会校验请求的路径是否是 `/login` ,如果不是的话就直接放行。
109+
110+
然后在从请求参数里面获取用户名和密码
111+
112+
- username
113+
- password
114+
115+
再之后使用 `DatabasirUserDetailsService` 根据用户名获取实际的用户信息,将实际的密码和登录时传的参数做比较
116+
117+
- 如果不一致就登录失败,调用 `DatabasirAuthenticationFailureHandler`
118+
- 如果一致就说明登录成功,调用 `DatabasirAuthenticationSuccessHandler`
119+
120+
下图展示了一个简化的代码调用时序
121+
122+
![](img/2-username-and-password-filter.png)
123+
124+
125+
126+
## 登录成功回调
127+
128+
当用户名密码认证通过以后就会触发**登录成功回调**(代码实现在`DatabasirAuthenticationSuccessHandler`),这里主要做一件事情
129+
130+
- 生成登录凭证:access_token、refresh_token
131+
132+
access_token 是请求接口的凭证,证明你是合法的登录用户,时效性是以分钟为单位,格式为 JWT。
133+
134+
refresh_token 是用于在 access_token 过期时,用于获取新的 access_token,时效性是以天为单位。
135+
136+
这些信息都存储在 login 表里,login 表与 user 表是一对一的关系
137+
138+
![](img/3-token.png)
139+
140+
access_token 和 refresh_token 最终都会返回给前端,前端拿到 token 以后调用业务接口都需在请求中加入 名为 Authorization 的 Header,值为 access_token
141+
142+
```http
143+
POST /api/v1.0/groups
144+
145+
Authorization: {{ access_token }}
146+
```
147+
148+
如果 access_token 过期,前端会拿 refresh_token 获取一个新的 access_token,然后再调用业务接口,这些过程对用户是透明的。
149+
150+
151+
152+
## 登录失败回调
153+
154+
当用户名密码认证没通过的时候机会触发登录失败回调,源码位于 `DatabasirAuthenticationFailureHandler` 中。
155+
156+
失败的回调会判断异常类型做出不同的响应
157+
158+
- BadCredentialsException:响应 200,用户名或密码错误
159+
- DisabledException:响应 200,用户已禁用
160+
- DatabasirAuthenticationException:响应 200,自定义登录异常
161+
- 其他:响应 401
22.1 KB
Loading
Lines changed: 58 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
# 模块和包
2-
3-
## 项目模块
1+
# 项目模块
42

53
Databasir 基于 Gradle 进行模块管理,当前共有 5 个模块
64

@@ -10,4 +8,60 @@ Databasir 基于 Gradle 进行模块管理,当前共有 5 个模块
108
| common | 定义了项目通用的类,比如加解密工具、业务异常、标准 HTTP 返回类型等 |
119
| core | 核心业务模块,包含了所有的业务逻辑 |
1210
| dao | 数据访问层,包含了数据库的实体、数据访问对象以及项目模型的 SQL 文件 |
13-
| plugin | jdbc 封装模块,将从 jdbc 获取的数据库元信息转换成 Databasir 的 Java 对象,文档信息的 DIFF 功能也是在该模块内实现 |
11+
| plugin | jdbc 封装模块,将从 jdbc 获取的数据库元信息转换成 Databasir 的 Java 对象,文档信息的 DIFF 功能也是在该模块内实现 |
12+
13+
模块的依赖关系是一个简单的单向依赖
14+
15+
![](img/module-relation.png)
16+
17+
18+
19+
## API 模块介绍
20+
21+
- 代码目录
22+
23+
```java
24+
api
25+
└── src/main/java
26+
└── com/databasir
27+
├── api
28+
│ ├── advice
29+
│ │ ├── DatabasirExceptionAdvice.java /* 业务异常切面 */
30+
│ │ └── OperationLogAspect.java /* 审计日志切面 */
31+
│ ├── common
32+
│ │ └── LoginUserContext.java 用户信息工具类
33+
│ ├── config
34+
│ │ ├── oauth2
35+
│ │ │ ├── DatabasirOAuth2Authentication.java /* oauth2 登录信息实体 */
36+
│ │ │ ├── DatabasirOauth2LoginFilter.java /* oauth2 登录过滤器 */
37+
│ │ │ └── OAuth2AuthenticationSuccessHandler.java /* oauth2 登录成功回调类 */
38+
│ │ ├── security
39+
│ │ │ ├── DatabasirAuthenticationEntryPoint.java /* 授权失败回调类 */
40+
│ │ │ ├── DatabasirAuthenticationFailureHandler.java /* 登录失败回调类 */
41+
│ │ │ ├── DatabasirAuthenticationSuccessHandler.java /* 登录成功回调类 */
42+
│ │ │ ├── DatabasirJwtTokenFilter.java /* jwt token 校验过滤器 */
43+
│ │ │ ├── DatabasirUserDetails.java /* 已登录用户实体信息 */
44+
│ │ │ └── DatabasirUserDetailService.java /* 加载 DatabasirUserDetails 的 service */
45+
│ │ ├── SecurityConfig.java /* spring security 配置类 */
46+
│ │ └── WebConfig.java /* web 配置类 */
47+
│ ├── validator
48+
│ │ └── XXXXXValidator.java /* 业务规则前置校验器 */
49+
│ ├── XXXXXController.java /* 业务 HTTP 接口 */
50+
│ └── Routes.java /* 业务 HTTP 接口路径常量 */
51+
└── job
52+
├── ProjectDocumentAutoSyncJob.java /* 文档自动同步任务 */
53+
└── ProjectDocumentAutoSyncTriggerJob.java /* 文档自动同步任务启用任务 */
54+
```
55+
56+
57+
58+
- 配置目录
59+
60+
```java
61+
api
62+
└── src/main/resources
63+
├── static /* 静态资源目录 */
64+
├── application.properties /* 生产环境配置文件 */
65+
└── application-local.properties /* 本地开发配置文件 */
66+
```
67+

docs/_sidebar.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
* 参与开发
2323
* [构建指南](README/develop/build/index.md)
2424
* [模块和包](README/develop/module-and-package/index.md)
25+
* 登录授权流程
26+
* [用户名密码登录流程](README/develop/login-and-auth/username-and-password/index.md)
2527

2628
* 捐赠
2729

docs/index.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,5 +36,6 @@
3636
<script src="//cdn.jsdelivr.net/npm/prismjs@1/components/prism-bash.min.js"></script>
3737
<script src="//cdn.jsdelivr.net/npm/prismjs@1/components/prism-sql.min.js"></script>
3838
<script src="//cdn.jsdelivr.net/npm/prismjs@1/components/prism-properties.min.js"></script>
39+
<script src="//cdn.jsdelivr.net/npm/prismjs@1/components/prism-java.min.js"></script>
3940
</body>
4041
</html>

0 commit comments

Comments
 (0)