Spring Security 是一个专注于为 Java 应用程序提供身份认证(Authentication)和授权(Authorization)的框架。
x1<!-- SpringBoot父工程 -->
2<parent>
3 <groupId>org.springframework.boot</groupId>
4 <artifactId>spring-boot-starter-parent</artifactId>
5 <version>3.2.0</version>
6</parent>
7
8<!-- GAV坐标 -->
9<groupId>com.example</groupId>
10<artifactId>SpringSecurity-demo</artifactId>
11<version>0.0.1-SNAPSHOT</version>
12
13<!-- 工程属性 -->
14<properties>
15 <java.version>17</java.version>
16</properties>
17
18<!-- 工程依赖 -->
19<dependencies>
20 <!-- spring-web -->
21 <dependency>
22 <groupId>org.springframework.boot</groupId>
23 <artifactId>spring-boot-starter-web</artifactId>
24 </dependency>
25
26 <!-- spring-security -->
27 <dependency>
28 <groupId>org.springframework.boot</groupId>
29 <artifactId>spring-boot-starter-security</artifactId>
30 </dependency>
31
32 <!-- thymeleaf -->
33 <dependency>
34 <groupId>org.springframework.boot</groupId>
35 <artifactId>spring-boot-starter-thymeleaf</artifactId>
36 </dependency>
37 <dependency>
38 <groupId>org.thymeleaf.extras</groupId>
39 <artifactId>thymeleaf-extras-springsecurity6</artifactId>
40 </dependency>
41
42 <!-- test -->
43 <dependency>
44 <groupId>org.springframework.boot</groupId>
45 <artifactId>spring-boot-starter-test</artifactId>
46 <scope>test</scope>
47 </dependency>
48 <dependency>
49 <groupId>org.springframework.security</groupId>
50 <artifactId>spring-security-test</artifactId>
51 <scope>test</scope>
52 </dependency>
53
54</dependencies>
55
56<!-- Maven插件 -->
57<build>
58 <plugins>
59 <plugin>
60 <groupId>org.springframework.boot</groupId>
61 <artifactId>spring-boot-maven-plugin</artifactId>
62 </plugin>
63 </plugins>
64</build>
在路径 resources/templates 中创建index.html
:
111<html xmlns:th="https://www.thymeleaf.org">
2<head>
3 <title>Hello Security!</title>
4</head>
5<body>
6<h1>Hello Security</h1>
7
8<!-- 当点击“登出”时,访问 SpringSecurity 提供的默认登出接口:/logout,进行登出操作 -->
9<a th:href="@{/logout}">登出</a>
10</body>
11</html>
注意:
- 资源地址使用
@{/资源地址}
引用,以适应不同的 Servlet 上下文路径
91
2public class IndexController {
3
4 // 访问 / 时,跳转 index 视图
5 "/") (
6 public String index() {
7 return "index";
8 }
9}
启动 SpringBoot 应用,在浏览器中访问:http://localhost:8080/,当未登录时,会自动跳转到登录页面:http://localhost:8080/login。
61
2public class Application {
3 public static void main(String[] args) {
4 SpringApplication.run(Application.class, args);
5 }
6}
默认登录用户为 user
,登陆密码可在控制台的启动日志中查看,或者通过 SpringBoot 属性进行修改:
31# application.yml -> SecurityProperties
2spring.security.user.name=user
3spring.security.user.password=123
注意:
- 由于默认登录页面在线引用了 github.com 的 bootstrap.min.css 样式,可能会加载缓慢及样式缺失。
Spring Security 底层是通过 Servlet 的 过滤器(Filter)
来拦截请求,并通过 SecurityFilterChain
来组装处理流程:
在使用用户名和密码进行登录时,默认通过 SecurityFilterChain 中的 UsernamePasswordAuthenticationFilter
进行凭证比对:
入门案例就是基于内存的身份认证,我们可以对 SpringSecurity 提供的 InMemoryUserDetailsManager
进行自定义配置和注册:
141
2// 注意:SpringBoot项目会根据 spring-security 依赖包自动配置该注解
3public class WebSecurityConfig {
4
5 public UserDetailsService userDetailsService() {
6 InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
7 manager.createUser(
8 User.withDefaultPasswordEncoder().username("admin") //自定义用户名
9 .password("123") //自定义密码
10 .roles("USER") //自定义角色
11 .build());
12 return manager;
13 }
14}
注意:
- 自定义 UserDetailsService 后,spring.security相关属性配置需自行应用。
181-- 创建数据库
2CREATE DATABASE `security-demo`;
3USE `security-demo`;
4
5-- 创建用户表
6CREATE TABLE `user`(
7 `id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
8 `username` VARCHAR(50) DEFAULT NULL ,
9 `password` VARCHAR(500) DEFAULT NULL,
10 `enabled` BOOLEAN NOT NULL
11);
12-- 唯一索引
13CREATE UNIQUE INDEX `user_username_uindex` ON `user`(`username`);
14
15-- 插入用户数据(密码是 "abc" )
16insert into user (id, username, password, enabled) values (1, 'admin', '{bcrypt}$2a$04$atzYEW3OCopaSwZkVE/ZoO6JcSfMIBwkFtpD4Vq9BN3QMgGwYsiw6', 1);
17insert into user (id, username, password, enabled) values (2, 'hyx', '{bcrypt}$2a$10$NwvCC8Bi3v4cFgTRizU7PuSqbGvsPnJ8TWROCrYZeQUEk5wuqvRXq', 1);
18
371<!-- jdbc -->
2<dependency>
3 <groupId>mysql</groupId>
4 <artifactId>mysql-connector-java</artifactId>
5 <version>8.0.30</version>
6</dependency>
7
8<!-- mybatis-plus -->
9<dependency>
10 <groupId>com.baomidou</groupId>
11 <artifactId>mybatis-plus-boot-starter</artifactId>
12 <version>3.5.4.1</version>
13 <exclusions>
14 <exclusion>
15 <groupId>org.mybatis</groupId>
16 <artifactId>mybatis-spring</artifactId>
17 </exclusion>
18 </exclusions>
19</dependency>
20<dependency>
21 <groupId>org.mybatis</groupId>
22 <artifactId>mybatis-spring</artifactId>
23 <version>3.0.3</version>
24</dependency>
25
26<!-- lombok -->
27<dependency>
28 <groupId>org.projectlombok</groupId>
29 <artifactId>lombok</artifactId>
30</dependency>
31
32<!-- json -->
33<dependency>
34 <groupId>com.alibaba.fastjson2</groupId>
35 <artifactId>fastjson2</artifactId>
36 <version>2.0.37</version>
37</dependency>
91#MySQL数据源
2spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
3spring.datasource.url=jdbc:mysql://119.29.250.81:3306/security-demo
4spring.datasource.username=root
5spring.datasource.password=123456
6
7#SQL日志
8mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
9
211// 实体类
2
3public class User {
4 value = "id", type = IdType.AUTO) (
5 private Integer id;
6 private String username;
7 private String password;
8 private Boolean enabled;
9}
10
11// Mapper
12
13public interface UserMapper extends BaseMapper<User> {
14}
15
16// Mapper XML
17// resources/mapper/UserMapper.xml
18<?xml version="1.0" encoding="UTF-8"?>
19<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
20<mapper namespace="com.atguigu.securitydemo.mapper.UserMapper">
21</mapper>
基于数据库的身份认证,需要自定义一个 UserDetailsManager
(继承自UserDetailsService),以支持从数据查询用户名和密码等信息:
701
2public class DBUserDetailsManager implements UserDetailsManager, UserDetailsPasswordService {
3
4
5 private UserMapper userMapper;
6
7 // 查询用户名和密码
8
9 public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
10
11 // 查询用户
12 User user = userMapper.selectOne(new QueryWrapper<User>().eq("username", username));
13 if (user == null) {
14 throw new UsernameNotFoundException(username);
15 }
16
17 // 转换为 SpringSecurity 的 User 对象
18 return new org.springframework.security.core.userdetails.User(
19 user.getUsername(),
20 user.getPassword(),
21 user.getEnabled(),
22 true, //用户账号是否过期
23 true, //用户凭证是否未过期
24 true, //用户是否未被锁定
25 new ArrayList<>()); //权限列表
26 }
27
28 // 更新用户密码
29
30 public UserDetails updatePassword(UserDetails userdetails, String newPassword) {
31 User user = new User();
32 user.setUsername(userdetails.getUsername());
33 user.setPassword(userdetails.getPassword());
34 userMapper.update(user, new QueryWrapper<User>().eq("username", user.getUsername()));
35 return loadUserByUsername(userdetails.getUsername());
36 }
37
38 // 新增用户
39
40 public void createUser(UserDetails userDetails) {
41 // 转换为业务 User,插入数据库
42 User user = new User();
43 user.setUsername(userDetails.getUsername());
44 user.setPassword(userDetails.getPassword());
45 user.setEnabled(true);
46 userMapper.insert(user);
47 }
48
49 // 更新
50
51 public void updateUser(UserDetails user) {
52
53 }
54
55
56 public void deleteUser(String username) {
57
58 }
59
60
61 public void changePassword(String oldPassword, String newPassword) {
62
63 }
64
65 // 检查用户是否存在
66
67 public boolean userExists(String username) {
68 return false;
69 }
70}
注意:
- UserDetailsManager中也可以增加和删除用户,以及修改用户密码等。
231// 接口
2public interface UserService extends IService<User> {
3 void saveUserDetails(User user);
4}
5
6// 实现
7
8public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
9
10 private DBUserDetailsManager dbUserDetailsManager;
11
12
13 public void saveUserDetails(User user) {
14
15 UserDetails userDetails = org.springframework.security.core.userdetails.User
16 .withDefaultPasswordEncoder() // 密码加密器
17 .username(user.getUsername()) // 用户名
18 .password(user.getPassword()) // 用户密码
19 .build();
20 dbUserDetailsManager.createUser(userDetails);
21
22 }
23}
注意:
- SpringSecurity 默认使用基于自适应单向函数的
BCryptPasswordEncoder
进行密码加密。
181
2"/user") (
3public class UserController {
4
5 public UserService userService;
6
7 // 查询所有用户
8 "/list") (
9 public List<User> getList() {
10 return userService.list();
11 }
12
13 // 新增用户
14 "/add") (
15 public void add( User user) {
16 userService.saveUserDetails(user);
17 }
18}
启动 SpringBoot 应用,测试如下:
新增配置类 WebSecurityConfig
如下,手动注册一个 SecurityFilterChain
来覆盖默认配置:
271
2
3public class WebSecurityConfig {
4
5 public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
6 // 开启授权保护
7 http.authorizeRequests(
8 // 对所有请求开启授权保护
9 authorize -> authorize.anyRequest()
10 // 已认证请求会自动被授权
11 .authenticated());
12
13 // 登录配置
14 http.formLogin(withDefaults())// 表单登录方式:使用 SpringSecurity 默认登录页
15 .httpBasic(withDefaults());// 基础登录方式:使用“浏览器弹窗提示”登录
16
17 // 关闭csrf攻击防御
18 http.csrf((csrf) -> {
19 csrf.disable();
20 });
21
22 // 支持跨域
23 http.cors(withDefaults());
24
25 return http.build();
26 }
27}
注意:
- SpringBoot 项目会根据 spring-security 依赖包自动配置
@EnableWebSecurity
注解。
访问http://localhost:8080/user/info 查询当前登录用户信息,返回 json 数据。
321
2"/user") (
3public class UserController {
4
5 public UserService userService;
6
7 // 获取当前登录用户信息
8 "/info") (
9 public Map test() {
10 // SpringSecurity上下文
11 SecurityContext context = SecurityContextHolder.getContext();
12
13 // 认证对象
14 Authentication authentication = context.getAuthentication();
15
16 // 认证信息
17 String username = authentication.getName(); // 用户名
18 Object credentials = authentication.getCredentials();// 用户凭证(注意脱敏展示)
19 Object principal = authentication.getPrincipal(); // 身份信息
20 Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities(); // 权限列表
21
22 // 返回
23 HashMap result = new HashMap();
24 result.put("code", 0);
25 result.put("username", username);
26 result.put("credentials", credentials);
27 result.put("principal", principal);
28 result.put("authorities", authorities);
29
30 return result;
31 }
32}
新增登录页面 templates/login.html 如下:
291
2<html xmlns:th="https://www.thymeleaf.org">
3<head>
4 <title>自定义登录页面</title>
5</head>
6<body>
7
8<h1>自定义登录页面</h1>
9<div th:if="${param.error}">用户名或密码不正确</div>
10
11<!-- 登录表单:-->
12<!-- 登录页:th:action="@{/login}" -->
13<!-- 请求方式:必须为 post -->
14<form th:action="@{/login}" method="post">
15
16 <!-- 用户名:默认为"username" -->
17 <div>
18 <input type="text" name="username" placeholder="用户名"/>
19 </div>
20
21 <!-- 用户密码:默认为"password" -->
22 <div>
23 <input type="password" name="password" placeholder="用户密码"/>
24 </div>
25
26 <input type="submit" value="登录"/>
27</form>
28</body>
29</html>
81
2public class LoginController {
3
4 "/login") (
5 public String login() {
6 return "login"; // 返回视图
7 }
8}
修改登录配置信息如下:
141// 登录配置
2http
3 // 表单登录方式:自定义登录页
4 .formLogin(form -> {
5 form.loginPage("/login") // 登录接口
6 .permitAll() // 登录页面无需授权即可访问
7 .usernameParameter("username") // 自定义表单用户名参数,默认是username
8 .passwordParameter("password") // 自定义表单密码参数,默认是password
9 .failureUrl("/login?error") // 登录失败的返回地址
10 ;
11 })
12
13 // 基础登录方式:使用“浏览器弹窗提示”登录
14 .httpBasic(withDefaults());
651// 登录成功
2public class MyAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
3
4 public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
5
6 // 获取用户身份信息
7 Object principal = authentication.getPrincipal();
8
9 // 创建结果对象
10 HashMap result = new HashMap();
11 result.put("code", 0);
12 result.put("message", "登录成功");
13 result.put("data", principal);
14
15 // 转换成json字符串
16 String json = JSON.toJSONString(result);
17
18 // 返回响应
19 response.setContentType("application/json;charset=UTF-8");
20 response.getWriter().println(json);
21 }
22}
23
24// 登录失败
25public class MyAuthenticationFailureHandler implements AuthenticationFailureHandler {
26
27
28 public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException {
29
30 // 获取错误信息
31 String localizedMessage = exception.getLocalizedMessage();
32
33 // 创建结果对象
34 HashMap result = new HashMap();
35 result.put("code", -1);
36 result.put("message", localizedMessage);
37
38 // 转换成json字符串
39 String json = JSON.toJSONString(result);
40
41 // 返回响应
42 response.setContentType("application/json;charset=UTF-8");
43 response.getWriter().println(json);
44 }
45}
46
47// 用户登出
48public class MyLogoutSuccessHandler implements LogoutSuccessHandler {
49
50
51 public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
52
53 // 创建结果对象
54 HashMap result = new HashMap();
55 result.put("code", 0);
56 result.put("message", "登出成功");
57
58 // 转换成json字符串
59 String json = JSON.toJSONString(result);
60
61 // 返回响应
62 response.setContentType("application/json;charset=UTF-8");
63 response.getWriter().println(json);
64 }
65}
修改登录/登出配置如下:
211// 登录配置
2http
3 // 表单登录方式:自定义登录页
4 .formLogin(form -> {
5 form.loginPage("/login") // 登录接口
6 .permitAll() // 登录页面无需授权即可访问
7 .usernameParameter("username") // 自定义表单用户名参数,默认是username
8 .passwordParameter("password") // 自定义表单密码参数,默认是password
9
10 .successHandler(new MyAuthenticationSuccessHandler()) // 认证成功时的处理
11 .failureHandler(new MyAuthenticationFailureHandler()) // 认证失败时的处理
12 ;
13 })
14
15 // 基础登录方式:使用“浏览器弹窗提示”登录
16 .httpBasic(withDefaults());
17
18// 登出配置
19http.logout(logout -> {
20 logout.logoutSuccessHandler(new MyLogoutSuccessHandler()); // 登出成功时的处理
21});
211// 未认证请求处理
2public class MyAuthenticationEntryPoint implements AuthenticationEntryPoint {
3
4 public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
5
6 // 获取错误信息
7 // String localizedMessage = authException.getLocalizedMessage();
8
9 // 创建结果对象
10 HashMap result = new HashMap();
11 result.put("code", -1);
12 result.put("message", "需要登录");
13
14 // 转换成json字符串
15 String json = JSON.toJSONString(result);
16
17 // 返回响应
18 response.setContentType("application/json;charset=UTF-8");
19 response.getWriter().println(json);
20 }
21}
修改错误处理配置如下:
41// 错误处理
2http.exceptionHandling(exception -> {
3 exception.authenticationEntryPoint(new MyAuthenticationEntryPoint()); // 请求未认证的接口
4});
限制用户只能在 1 处登录如下:
181public class MySessionInformationExpiredStrategy implements SessionInformationExpiredStrategy {
2
3 public void onExpiredSessionDetected(SessionInformationExpiredEvent event) throws IOException, ServletException {
4
5 // 创建结果对象
6 HashMap result = new HashMap();
7 result.put("code", -1);
8 result.put("message", "该账号已从其他设备登录");
9
10 // 转换成json字符串
11 String json = JSON.toJSONString(result);
12
13 HttpServletResponse response = event.getResponse();
14 // 返回响应
15 response.setContentType("application/json;charset=UTF-8");
16 response.getWriter().println(json);
17 }
18}
修改会话管理配置如下:
61// 会话管理
2http.sessionManagement(session -> {
3 session
4 .maximumSessions(1) // 最多在 1 处登录
5 .expiredSessionStrategy(new MySessionInformationExpiredStrategy());
6});
授权管理一般有如下两种模型:
161public class MyAccessDeniedHandler implements AccessDeniedHandler {
2
3 public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
4 // 创建结果对象
5 HashMap result = new HashMap();
6 result.put("code", -1);
7 result.put("message", "没有权限");
8
9 // 转换成json字符串
10 String json = JSON.toJSONString(result);
11
12 // 返回响应
13 response.setContentType("application/json;charset=UTF-8");
14 response.getWriter().println(json);
15 }
16}
修改错误处理配置如下:
51// 错误处理
2http.exceptionHandling(exception -> {
3 exception.authenticationEntryPoint(new MyAuthenticationEntryPoint()); // 请求未认证的接口
4 exception.accessDeniedHandler(new MyAccessDeniedHandler()); // 请求未授权的接口
5});
在配置中开启授权保护如下:
121// 开启授权保护
2http.authorizeRequests(
3 authorize -> authorize
4 // 具有USER_LIST权限的用户可以访问/user/list
5 .requestMatchers("/user/list").hasAuthority("USER_LIST")
6 // 具有USER_ADD权限的用户可以访问/user/add
7 .requestMatchers("/user/add").hasAuthority("USER_ADD")
8 // 对所有请求开启授权保护
9 .anyRequest()
10 // 已认证的请求会被自动授权
11 .authenticated()
12);
在加载用户时设置用户权限如下:
241
2public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
3
4 // 查询用户
5 User user = userMapper.selectOne(new QueryWrapper<User>().eq("username", username));
6 if (user == null) {
7 throw new UsernameNotFoundException(username);
8 }
9
10 // 用户权限
11 Collection<GrantedAuthority> authorities = new ArrayList<>();
12 authorities.add(() -> "USER_LIST");
13 // authorities.add(() -> "USER_ADD");
14
15 // 转换为 SpringSecurity 的 User 对象
16 return new org.springframework.security.core.userdetails.User(
17 user.getUsername(),
18 user.getPassword(),
19 user.getEnabled(),
20 true, //用户账号是否过期
21 true, //用户凭证是否未过期
22 true, //用户是否未被锁定
23 authorities); //权限列表
24}
测试结果和结论如下:
491// 1. 有权限的资源能够访问
2http://127.0.0.1:8080/user/list
3[
4 {
5 "id": 1,
6 "username": "admin",
7 "password": "{bcrypt}$2a$04$atzYEW3OCopaSwZkVE/ZoO6JcSfMIBwkFtpD4Vq9BN3QMgGwYsiw6",
8 "enabled": true
9 },
10 {
11 "id": 2,
12 "username": "hyx",
13 "password": "{bcrypt}$2a$10$NwvCC8Bi3v4cFgTRizU7PuSqbGvsPnJ8TWROCrYZeQUEk5wuqvRXq",
14 "enabled": true
15 }
16]
17
18// 2. 无权限的资源不能访问
19http://127.0.0.1:8080/user/add
20{
21 "code": -1,
22 "message": "没有权限"
23}
24
25// 3. 未配置权限保护的接口也可以访问
26http://127.0.0.1:8080/user/info
27{
28 "principal": {
29 "password": null,
30 "username": "admin",
31 "authorities": [
32 {
33 "authority": "USER_LIST"
34 }
35 ],
36 "accountNonExpired": true,
37 "accountNonLocked": true,
38 "credentialsNonExpired": true,
39 "enabled": true
40 },
41 "code": 0,
42 "credentials": null,
43 "authorities": [
44 {
45 "authority": "USER_LIST"
46 }
47 ],
48 "username": "admin"
49}
注意:
- 用户的权限以及各权限对应的资源一般在数据库配置并加载。
在配置中开启授权保护如下:
101// 开启授权保护
2http.authorizeRequests(
3 authorize -> authorize
4 // 具有管理员角色的用户可以访问/user/**
5 .requestMatchers("/user/**").hasRole("ADMIN")
6 // 对所有请求开启授权保护
7 .anyRequest()
8 // 已认证的请求会被自动授权
9 .authenticated()
10);
在加载用户时设置用户权限如下:
161
2public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
3
4 // 查询用户
5 User user = userMapper.selectOne(new QueryWrapper<User>().eq("username", username));
6 if (user == null) {
7 throw new UsernameNotFoundException(username);
8 }
9
10 // 转换为 SpringSecurity 的 User 对象
11 return org.springframework.security.core.userdetails.User
12 .withUsername(user.getUsername())
13 .password(user.getPassword())
14 .roles("ADMIN") // 设置ADMIN角色
15 .build();
16}
此时,只有 ADMIN
角色的用户可以访问 /user/**
资源。
在配置类上开启基于控制器方法的授权:
51
2
3public class WebSecurityConfig {
4 // ...
5}
131// 用户必须有 ADMIN 角色 并且 用户名是 admin 才能访问此方法
2"/list") (
3"hasRole('ADMIN') and authentication.name == 'admim'") (
4public List<User> getList(){
5 return userService.list();
6}
7
8// 用户必须有 USER_ADD 权限 才能访问此方法
9"/add") (
10"hasAuthority('USER_ADD')") (
11public void add( User user){
12 userService.saveUserDetails(user);
13}
171
2public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
3
4 // 查询用户
5 User user = userMapper.selectOne(new QueryWrapper<User>().eq("username", username));
6 if (user == null) {
7 throw new UsernameNotFoundException(username);
8 }
9
10 // 转换为 SpringSecurity 的 User 对象
11 return org.springframework.security.core.userdetails.User
12 .withUsername(user.getUsername())
13 .password(user.getPassword())
14 .roles("ADMIN") // 角色
15 .authorities("USER_ADD", "USER_UPDATE") // 权限
16 .build();
17}
OAuth(Open Authorization) 是一个关于授权(authorization)的开放网络协议,允许用户授权第三方应用访问存储在其他服务提供者上的信息,并且不需要将用户名和密码直接提供给第三方应用。
它包括如下四个角色:
JSON Web Tokens(JWT)是一种基于 JSON 的开放标准(RFC 7519),一般被用来在身份提供者和服务提供者之间传递被认证的用户身份信息,以便于从资源服务器获取资源。每个JWT都是经过数字签名的,因此可以被验证和信任。
JWT通常包含三部分:
171// JWT
2eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9 \
3.eyJzdWIiOiJzYXRpc2giLCJhdWQiOiJteWFwcCIsIkNVU1QiOiIxIiwiZXhwIjoxNTY2MjE0NTg1LCJpc3MiOiJhdXRoLWFwcCJ9 \
4.WknG6jiM_vAaflLnKyjlXh5BrM4MUJR9dFrVx-XE3zRVWiyXeIVzI-OomFh0vVHRwrK3-Tttg0HyKBTnCA3mSg
5
6// 解码后
7Header: {
8 "alg": "HS512",
9 "typ": "JWT"
10}
11Payload: {
12 "sub": "satish",
13 "aud": "myapp",
14 "CUST": "1",
15 "exp": 1566214585,
16 "iss": "my-auth-app"
17}
【小家思想】通俗易懂版讲解JWT和OAuth2,以及他俩的区别和联系(Token鉴权解决方案)-腾讯云开发者社区-腾讯云
深入 OAuth2.0 和 JWT_oauth2.0与jwt-CSDN博客
【鉴权】session、token、jwt、oauth2-支付宝开发者社区