# SpringBoot单体服务版配置 Oauth2.0
- 数据库:PostgresSQL
- 开发工具:idea
- 开发框架:SpringBoot
- 数据库操作:MyBatisPlus
- 实体类工具:lombok
# 数据库配置
RBAC 是基于角色的访问控制(Role-Based Access Control )在RBAC中,权限与角色相关联,用户通过成为适当角色的成员而得到这些角色的权限。这就极大地简化了权限的管理。这样管理都是层级相互依赖的,权限赋予给角色,而把角色又赋予用户,这样的权限设计很清楚,管理起来很方便。

# 用户表
create table auth_user
(
uuid uuid default uuid_generate_v4() not null
constraint auth_user_pkey
primary key,
id bigserial not null,
username varchar(128) not null,
password varchar(128) not null,
phone_number varchar(128),
email varchar(128),
is_deleted boolean default false,
is_enable boolean default true,
is_show boolean default true,
revision integer default 0,
created_by varchar(32) default 'bztdt_admin'::character varying,
created_time date default now(),
updated_by varchar(32) default 'bztdt_admin'::character varying,
updated_time date default now()
);
comment on table auth_user is '用户信息表';
comment on column auth_user.uuid is '唯一ID';
comment on column auth_user.id is '自增id';
comment on column auth_user.username is '不能重复,不能过长';
comment on column auth_user.password is '进行加密';
comment on column auth_user.phone_number is '13位';
comment on column auth_user.email is '符合规范';
comment on column auth_user.is_deleted is '删除时,将字段设置为true';
comment on column auth_user.is_enable is '是否启用账号';
comment on column auth_user.is_show is '管理员账号不显示';
comment on column auth_user.revision is '默认为0,每次修改加一';
comment on column auth_user.created_by is '默认为admin';
comment on column auth_user.created_time is '创建时间';
comment on column auth_user.updated_by is '默认为admin';
comment on column auth_user.updated_time is '更新时间';
alter table auth_user
owner to postgres;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# 角色表
create table auth_role
(
id bigserial not null
constraint auth_role_pkey
primary key,
parent_id bigint,
name varchar(128) not null,
enname varchar(128) not null,
description varchar(512),
is_deleted boolean default false,
sort_code varchar(32),
revision integer default 0,
created_by varchar(32) default 'bztdt_admin'::character varying,
created_time date default now(),
updated_by varchar(32) default 'bztdt_admin'::character varying,
updated_time date default now()
);
comment on table auth_role is '角色表';
comment on column auth_role.id is '唯一值';
comment on column auth_role.parent_id is '父角色';
comment on column auth_role.name is '角色名称';
comment on column auth_role.enname is '角色英文名称';
comment on column auth_role.description is '备注';
comment on column auth_role.is_deleted is '是否删除';
comment on column auth_role.sort_code is '排序代码';
comment on column auth_role.revision is '乐观锁';
comment on column auth_role.created_by is '创建人';
comment on column auth_role.created_time is '创建时间';
comment on column auth_role.updated_by is '更新人';
comment on column auth_role.updated_time is '更新时间';
alter table auth_role
owner to postgres;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# 权限表
create table auth_permission
(
id bigserial not null
constraint auth_permission_pkey
primary key,
parent_id bigint,
name varchar(128) not null,
enname varchar(128) not null,
url varchar(1024) not null,
resource_id varchar(32) default 'resources'::character varying not null,
is_deleted boolean default false,
sort_code varchar(32),
revision integer default 0,
created_by varchar(32) default 'bztdt_admin'::character varying,
created_time date default now(),
updated_by varchar(32) default 'bztdt_admin'::character varying,
updated_time date default now()
);
comment on table auth_permission is '权限表,后台接口访问权限管理';
comment on column auth_permission.id is '唯一id';
comment on column auth_permission.parent_id is '父权限';
comment on column auth_permission.name is '权限名称';
comment on column auth_permission.enname is '权限英文名称';
comment on column auth_permission.url is '授权路径';
comment on column auth_permission.resource_id is '资源服务器id';
comment on column auth_permission.is_deleted is '是否删除';
comment on column auth_permission.sort_code is '排序代码';
comment on column auth_permission.revision is '乐观锁';
comment on column auth_permission.created_by is '创建人';
comment on column auth_permission.created_time is '创建时间';
comment on column auth_permission.updated_by is '更新人';
comment on column auth_permission.updated_time is '更新时间';
alter table auth_permission
owner to postgres;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# 用户角色表
create table auth_user_role
(
id bigserial not null
constraint auth_user_role_pkey
primary key,
role_id bigint not null,
user_id uuid
);
comment on table auth_user_role is '用户角色表';
comment on column auth_user_role.id is '唯一id';
comment on column auth_user_role.role_id is '角色id';
alter table auth_user_role
owner to postgres;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 角色权限表
create table auth_role_permission
(
id bigserial not null
constraint auth_role_permission_pkey
primary key,
role_id bigint not null,
permission_id bigint not null
);
comment on table auth_role_permission is '角色权限表';
comment on column auth_role_permission.id is '唯一id';
comment on column auth_role_permission.role_id is '角色ID';
comment on column auth_role_permission.permission_id is '权限ID';
alter table auth_role_permission
owner to postgres;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 代码
# 项目结构

- 启用密码模式
- 使用Redis存储令牌
- 单体项目认证服务器和资源服务器在同一个项目中
# pom文件
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.6.RELEASE</version>
<relativePath/>
</parent>
<groupId>com.sun</groupId>
<artifactId>test</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>test</name>
<description>test</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- Spring Cloud -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-oauth2</artifactId>
<version>2.2.2.RELEASE</version>
</dependency>
<!--数据库相关-->
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.0</version>
</dependency>
<!-- redis -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!--tools-->
<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>
</project>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
# application.yml文件
server:
port: 8888
url: localhost
spring:
servlet:
multipart:
max-file-size: -1MB
max-request-size: -1MB
mvc:
async:
request-timeout: 20000
devtools:
restart:
enabled: false
additional-paths: src/main/java
exclude: WEB-INF/**
datasource:
url: jdbc:postgresql://${base.config.db.hostname}:${base.config.db.port}/${base.config.db.db}?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
username: ${base.config.db.username}
password: ${base.config.db.password}
driver-class-name: org.postgresql.Driver
type: com.zaxxer.hikari.HikariDataSource
hikari:
minimum-idle: 5
idle-timeout: 600000
maximum-pool-size: 10
auto-commit: true
pool-name: MyHikariCP
max-lifetime: 1800000
connection-timeout: 30000
connection-test-query: SELECT 1
redis:
port: ${base.config.redis.port}
host: ${base.config.redis.hostname}
password: ${base.config.redis.password}
database: 0
timeout: 10000
jedis:
pool:
max-active: 200
max-wait: -1
max-idle: 10
min-idle: 0
mybatis:
mapper-locations: classpath*:mapper/*.xml
type-aliases-package: com.sun.test.entity
configuration:
map-underscore-to-camel-case: true
security:
oauth2:
client:
client-id: client
client-secret: secret
access-token-uri: http://${server.url}:${server.port}/oauth/token
user-authorization-uri: http://${server.url}:${server.port}/oauth/authorize
resource:
token-info-uri: http://${server.url}:${server.port}/oauth/check_token
authorization:
check-token-access: http://${server.url}:${server.port}/oauth/check_token
oauth2:
grant_type: password
client_id: client
client_secret: secret
logging:
level:
com.zykj.bztdt.mapper: debug
base:
config:
db:
hostname: 192.168.1.111
port: 5432
db: test
username: postgres
password: postgres
redis:
hostname: 192.168.1.96
port: 6379
password: 123456
database: 0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# 实体类
# 用户信息实体类
- AuthUser
import java.time.LocalDate;
import java.io.Serializable;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* <p>
* 用户信息表
* </p>
*
* @author sung
* @since 2021-05-25
*/
@Data
@EqualsAndHashCode(callSuper = false)
public class AuthUser implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 唯一ID
*/
private String uuid;
/**
* 自增id
*/
private Long id;
/**
* 不能重复,不能过长
*/
private String username;
/**
* 进行加密
*/
private String password;
/**
* 13位
*/
private String phoneNumber;
/**
* 符合规范
*/
private String email;
/**
* 删除时,将字段设置为true
*/
private Boolean isDeleted;
/**
* 管理员账号不显示
*/
private Boolean isShow;
/**
* 是否启用账号
*/
private Boolean isEnable;
/**
* 默认为0,每次修改加一
*/
private Integer revision;
/**
* 默认为admin
*/
private String createdBy;
/**
* 创建时间
*/
private LocalDate createdTime;
/**
* 默认为admin
*/
private String updatedBy;
/**
* 更新时间
*/
private LocalDate updatedTime;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# 角色实体类
- AuthRole
import java.time.LocalDate;
import java.io.Serializable;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* <p>
* 用户信息表
* </p>
*
* @author sung
* @since 2021-05-25
*/
@Data
@EqualsAndHashCode(callSuper = false)
public class AuthUser implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 唯一ID
*/
private String uuid;
/**
* 自增id
*/
private Long id;
/**
* 不能重复,不能过长
*/
private String username;
/**
* 进行加密
*/
private String password;
/**
* 13位
*/
private String phoneNumber;
/**
* 符合规范
*/
private String email;
/**
* 删除时,将字段设置为true
*/
private Boolean isDeleted;
/**
* 管理员账号不显示
*/
private Boolean isShow;
/**
* 是否启用账号
*/
private Boolean isEnable;
/**
* 默认为0,每次修改加一
*/
private Integer revision;
/**
* 默认为admin
*/
private String createdBy;
/**
* 创建时间
*/
private LocalDate createdTime;
/**
* 默认为admin
*/
private String updatedBy;
/**
* 更新时间
*/
private LocalDate updatedTime;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# 权限实体类
- AuthPermission
import java.time.LocalDate;
import java.io.Serializable;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* <p>
* 权限表,后台接口访问权限管理
* </p>
*
* @author sung
* @since 2021-05-25
*/
@Data
@EqualsAndHashCode(callSuper = false)
public class AuthPermission implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 唯一id
*/
private Long id;
/**
* 父权限
*/
private Long parentId;
/**
* 权限名称
*/
private String name;
/**
* 权限英文名称
*/
private String enname;
/**
* 授权路径
*/
private String url;
/**
* 是否删除
*/
private Boolean isDeleted;
/**
* 排序代码
*/
private String sortCode;
/**
* 乐观锁
*/
private Integer revision;
/**
* 创建人
*/
private String createdBy;
/**
* 创建时间
*/
private LocalDate createdTime;
/**
* 更新人
*/
private String updatedBy;
/**
* 更新时间
*/
private LocalDate updatedTime;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
# 用户角色实体类
- AuthUserRole
import java.io.Serializable;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* <p>
* 用户角色表
* </p>
*
* @author sung
* @since 2021-05-25
*/
@Data
@EqualsAndHashCode(callSuper = false)
public class AuthUserRole implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 唯一id
*/
private Long id;
/**
* 角色id
*/
private Long roleId;
/**
* 用户id
*/
private Long userId;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# 角色权限实体类
- AuthRolePermission
import java.io.Serializable;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* <p>
* 角色权限表
* </p>
*
* @author sung
* @since 2021-05-25
*/
@Data
@EqualsAndHashCode(callSuper = false)
public class AuthRolePermission implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 唯一id
*/
private Long id;
/**
* 角色ID
*/
private Long roleId;
/**
* 权限ID
*/
private Long permissionId;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# Mapper层服务
# 用户信息表 Mapper 接口
import com.sun.test.entity.AuthUser;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
/**
* <p>
* 用户信息表 Mapper 接口
* </p>
*
* @author sung
* @since 2021-05-25
*/
public interface AuthUserMapper extends BaseMapper<AuthUser> {
/**
* 通过用户名获取用户信息
*
* @param username 用户名
* @return User
*/
AuthUser getInfoByName(String username);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
xml配置
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.sun.test.mapper.AuthUserMapper">
<select id="getInfoByName" resultType="com.zykj.bztdt.entity.AuthUser">
select * from auth_user where username=#{username}
</select>
</mapper>
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
# 权限信息获取接口
import com.sun.test.entity.AuthPermission;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import java.util.List;
/**
* <p>
* 权限表,后台接口访问权限管理 Mapper 接口
* </p>
*
* @author sung
* @since 2021-05-25
*/
public interface AuthPermissionMapper extends BaseMapper<AuthPermission> {
/**
* 通过资源服务器id,获取所有的权限地址
*
* @param resourceId 资源服务器id
* @return list
*/
List<AuthPermission> getAllUrlByResourceId(String resourceId);
/**
* 通过用户uuid获取用户权限
*
* @param userId 用户id
* @return list
*/
List<AuthPermission> selectByUserId(String userId);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
xml配置
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.sun.test.mapper.AuthPermissionMapper">
<select id="getAllUrlByResourceId" resultType="com.sun.test.entity.AuthPermission">
select *
from auth_permission
where resource_id = #{resourceId};
</select>
<select id="selectByUserId" resultType="com.sun.test.entity.AuthPermission">
select p.*
from auth_user as u
right join auth_user_role as ur
on u.uuid = ur.user_id
right join auth_role as r
on ur.role_id = r.id
right join auth_role_permission as rp
on r.id = rp.role_id
right join auth_permission as p
on rp.permission_id = p.id and p.is_deleted=false
where u.uuid = #{userId}::uuid
</select>
</mapper>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 认证服务器配置
# 服务器安全配置
WebSecurityConfiguration
创建一个类继承 WebSecurityConfigurerAdapter 并添加相关注解:
@Configuration@EnableWebSecurity@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true, jsr250Enabled = true):全局方法拦截
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
/**
* @author sungang
* 认证服务器安全配置
*/
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true, jsr250Enabled = true)
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
//配置加密方式
@Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
@Override
public UserDetailsService userDetailsServiceBean() {
return new UserDetailsServiceImpl();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsServiceBean());
}
/**
* 用于支持password模式
*/
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
String[] SWAGGER_WHITELIST = {
"/swagger-ui.html",
"/swagger-ui/*",
"/swagger-resources/**",
"/v2/api-docs",
"/v3/api-docs",
"/webjars/**"
};
@Override
public void configure(WebSecurity web) throws Exception {
//配置忽略的接口
web.ignoring()
.antMatchers("/auth/**")
.antMatchers("/oauth/check_token")
.antMatchers(SWAGGER_WHITELIST);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
# 自定义认证授权实现类
UserDetailsServiceImpl
创建一个类,实现 UserDetailsService 接口,代码如下:
import com.google.common.collect.Lists;
import com.zykj.bztdt.entity.AuthPermission;
import com.zykj.bztdt.entity.AuthUser;
import com.zykj.bztdt.mapper.AuthPermissionMapper;
import com.zykj.bztdt.mapper.AuthUserMapper;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;
/**
* @author sun
*/
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
@Resource
AuthUserMapper authUserMapper;
@Resource
AuthPermissionMapper authPermissionMapper;
@Override
public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
AuthUser user = authUserMapper.getInfoByName(s);
if (user != null) {
List<GrantedAuthority> grantedAuthorities = Lists.newArrayList();
List<AuthPermission> permissions = authPermissionMapper.selectByUserId(user.getUuid());
for (AuthPermission p : permissions
) {
SimpleGrantedAuthority roleUser = new SimpleGrantedAuthority(p.getEnname());
grantedAuthorities.add(roleUser);
}
return new org.springframework.security.core.userdetails.User(user.getUsername(), user.getPassword(), grantedAuthorities);
}
return null;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
令牌有多种存储方式,每种方式都是实现了 TokenStore 接口
- 存储在本机内存: InMemoryTokenStore
- 存储在数据库: JdbcTokenStore
- JWT: JwtTokenStore,Json Web Token 不会存储在任何介质中,不过我还是不推荐这种做法啊,并发 2w 以后会有问题哒,谁用谁知道额
- 存储在 Redis: RedisTokenStore
# 配置认证服务器
AuthorizationServerConfiguration
创建一个类继承 AuthorizationServerConfigurerAdapter 并添加相关注解:
@Configuration@EnableAuthorizationServer
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStore;
import javax.annotation.Resource;
/**
* @author sungang
* 配置认证服务器
*/
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {
@Resource
private BCryptPasswordEncoder passwordEncoder;
/**
* 注入用于支持password模式
*/
@Resource
private AuthenticationManager authenticationManager;
@Resource
private RedisConnectionFactory redisConnectionFactory;
/**
* Refresh Token 时需要自定义实现,否则抛异常 <br>
* Lazy 注解是为了防止循环注入(is there an unresolvable circular reference?)
*/
@Lazy
@Resource(name = "userDetailsServiceBean")
private UserDetailsService userDetailsService;
/**
* 注入redis工厂的bean
*/
@Bean
public TokenStore tokenStore() {
return new RedisTokenStore(redisConnectionFactory);
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
// 用于支持密码模式
endpoints.authenticationManager(authenticationManager).tokenStore(tokenStore());
// Refresh Token 时需要自定义实现,否则抛异常
endpoints.userDetailsService(userDetailsService);
}
@Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
security
// 允许客户端访问/oauth/check_token 检查token
.checkTokenAccess("isAuthenticated()")
.allowFormAuthenticationForClients();
}
/**
* 配置客户端
*
* @param clients 客户端连接
* @throws Exception 异常
*/
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients
// 使用内存设置
.inMemory()
// client_id
.withClient("client")
// client_secret
.secret(passwordEncoder.encode("secret"))
// 授权类型,密码模式和刷新令牌
.authorizedGrantTypes("password", "refresh_token")
// 授权范围
.scopes("backend")
// 可以设置对哪些资源有访问权限,不设置则全部资源都可以访问
.resourceIds("resources")
// 设置访问令牌的有效期,这里是1天
.accessTokenValiditySeconds(60 * 60 * 24)
// 设置刷新令牌的有效期,这里是30天
.refreshTokenValiditySeconds(60 * 60 * 24 * 30);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
# 资源服务器配置
ResourceServerConfiguration
创建一个类继承 ResourceServerConfigurerAdapter 并添加相关注解:
@Configuration@EnableResourceServer:资源服务器@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true, jsr250Enabled = true):全局方法拦截
import com.zykj.bztdt.service.PermitService;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
import javax.annotation.Resource;
import java.util.Map;
/**
* @author sungang
* <p>
* 资源服务管理
*/
@Configuration
@EnableResourceServer
public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
@Resource
private PermitService permissionService;
@Override
public void configure(HttpSecurity http) throws Exception {
// 管理员授权请求路径
//从数据库动态获取可访问权限地址
Map<String, String> map = permissionService.getAllUrlByResourceId("resources");
ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry
expressionInterceptUrlRegistry = http.exceptionHandling()
.and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and().authorizeRequests();
for (String key : map.keySet()) {
expressionInterceptUrlRegistry.antMatchers(key).hasAnyAuthority(map.get(key));
}
}
@Override
public void configure(ResourceServerSecurityConfigurer resource) throws Exception {
//指定Token异常信息
resource.authenticationEntryPoint(new AuthExceptionEntryPoint()).accessDeniedHandler(new CustomAccessDeniedHandler());
//设置资源服务器id
resource.resourceId("resources").stateless(true);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# 权限控制service
import java.util.Map;
/**
* @author sungang
* @date 2021/5/26 8:51 上午
* 权限控制使用
*/
public interface PermitService {
/**
* 通过资源服务器id,获取所有的权限地址
*
* @param resourceId 资源服务器id
* @return map
*/
Map<String, String> getAllUrlByResourceId(String resourceId);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
权限控制实现类
import com.sun.test.entity.AuthPermission;
import com.sun.test.mapper.AuthPermissionMapper;
import com.sun.test.service.PermitService;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author sungang
* @date 2021/5/26 8:51 上午
*/
@Service
public class PermitServiceImpl implements PermitService {
@Resource
AuthPermissionMapper authPermissionMapper;
@Override
public Map<String, String> getAllUrlByResourceId(String resourceId) {
List<AuthPermission> allUrlByResourceId = authPermissionMapper.getAllUrlByResourceId(resourceId);
Map<String, String> map = new HashMap<>();
for (AuthPermission p : allUrlByResourceId
) {
map.put(p.getUrl(), p.getEnname());
}
return map;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
这里使用到的mapper是上面的AuthPermissionMapper
# 配置自定义的异常处理
# 权限不足异常类重写
- CustomAccessDeniedHandler
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.stereotype.Component;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
/**
* @author sungang
* 权限不足异常类重写
*/
@Component("customAccessDeniedHandler")
public class CustomAccessDeniedHandler implements AccessDeniedHandler {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
response.setContentType("application/json;charset=UTF-8");
Map<String, Object> map = new HashMap<String, Object>();
map.put("code", "403");
map.put("msg", "权限不足");
map.put("data", accessDeniedException.getMessage());
map.put("success", false);
map.put("path", request.getServletPath());
map.put("timestamp", String.valueOf(System.currentTimeMillis()));
ObjectMapper mapper = new ObjectMapper();
response.setContentType("application/json");
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.getWriter().write(mapper.writeValueAsString(map));
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# 无效token异常重写
- AuthExceptionEntryPoint
import com.fasterxml.jackson.databind.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.oauth2.common.exceptions.InvalidTokenException;
import org.springframework.security.web.AuthenticationEntryPoint;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
/**
* @author sungang
* 无效token异常重写
*/
public class AuthExceptionEntryPoint implements AuthenticationEntryPoint {
private static final Logger log = LoggerFactory.getLogger(AuthExceptionEntryPoint.class);
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
Map<String, Object> map = new HashMap<String, Object>();
Throwable cause = authException.getCause();
if (cause instanceof InvalidTokenException) {
map.put("code", "401");
map.put("msg", "无效的token");
} else {
map.put("code", "401");
map.put("msg", "访问此资源需要完全的身份验证!");
}
map.put("data", authException.getMessage());
map.put("success", false);
map.put("path", request.getServletPath());
map.put("timestamp", String.valueOf(System.currentTimeMillis()));
response.setContentType("application/json");
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
try {
ObjectMapper mapper = new ObjectMapper();
mapper.writeValue(response.getOutputStream(), map);
} catch (Exception e) {
log.error(e.getMessage());
throw new ServletException();
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# Controller接口
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import com.sun.test.entity.pojo.LoginPojo;
import com.sun.test.response.ResponseCode;
import com.sun.test.response.ResponseResult;
import com.sun.test.service.AuthService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.Map;
/**
* @author sungang
* @date 2021/5/26 1:21 下午
* <p>
* 用户基础权限控制
*/
@Api(tags = "01-用户基础权限控制")
@RestController
@RequestMapping(value = "/auth")
public class AuthController {
@Resource
AuthService authService;
@ApiOperationSupport(order = 1)
@ApiOperation("用户登录")
@PostMapping(value = "login")
public ResponseResult login(@RequestBody LoginPojo loginPojo) {
return authService.login(loginPojo);
}
@ApiOperationSupport(order = 2)
@PostMapping("logout")
@ApiOperation("用户注销")
public ResponseResult logout(@RequestParam("accessToken") String accessToken) {
return authService.logout(accessToken);
}
@ApiOperationSupport(order = 3)
@ApiOperation("刷新access_token")
@ApiImplicitParams({
@ApiImplicitParam(name = "accessToken", value = "用户token", required = true, dataType = "String")
})
@PostMapping(value = "refresh")
public ResponseResult refresh(@RequestParam("accessToken") String accessToken) {
Map<String, String> refresh = authService.refresh(accessToken);
return new ResponseResult(ResponseCode.SUCCESS, refresh);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
# Service接口
import com.sun.test.entity.pojo.LoginPojo;
import com.sun.test.response.ResponseResult;
import java.util.Map;
/**
* @author sungang
* @date 2021/5/26 1:27 下午
* <p>
* 用户基础权限控制
*/
public interface AuthService {
/**
* 用戶登录验证接口
*
* @param loginPojo 用户登录实体类
* @return ResponseResult
*/
ResponseResult login(LoginPojo loginPojo);
/**
* 用户注销
*
* @param accessToken token
* @return ResponseResult
*/
ResponseResult logout(String accessToken);
/**
* 刷新Token
*
* @param accessToken 使用旧Token换取新Token
* @return Map
*/
Map<String, String> refresh(String accessToken);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# Service实现类
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.sun.test.entity.AuthUser;
import com.sun.test.entity.pojo.LoginPojo;
import com.sun.test.exception.BizException;
import com.sun.test.mapper.AuthUserMapper;
import com.sun.test.response.ResponseCode;
import com.sun.test.response.ResponseResult;
import com.sun.test.service.AuthService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
/**
* @author sungang
* @date 2021/5/26 1:28 下午
*/
@Service
public class AuthServiceImpl implements AuthService {
@Resource
public BCryptPasswordEncoder passwordEncoder;
@Resource
public TokenStore tokenStore;
@Resource(name = "userDetailsServiceBean")
public UserDetailsService userDetailsService;
@Value("${security.oauth2.client.access-token-uri}")
private String accessTokenUri;
@Value("${oauth2.grant_type}")
public String oauth2GrantType;
@Value("${oauth2.client_id}")
public String oauth2ClientId;
@Value("${oauth2.client_secret}")
public String oauth2ClientSecret;
@Resource
private RedisTemplate redisTemplate;
@Resource
AuthUserMapper userMapper;
@Override
public ResponseResult login(LoginPojo loginPojo) {
Map<String, Object> result = new HashMap<>();
AuthUser user = userMapper.getInfoByName(loginPojo.getUsername());
if (user == null) {
return new ResponseResult(ResponseCode.FAILURE, "账号不存在!");
}
if (user.getIsDeleted()) {
return new ResponseResult(ResponseCode.FAILURE, "账号已被删除,请联系管理员!");
}
UserDetails userDetails = userDetailsService.loadUserByUsername(loginPojo.getUsername());
if (userDetails == null || !passwordEncoder.matches(loginPojo.getPassword(), userDetails.getPassword())) {
return new ResponseResult(ResponseCode.FAILURE, "账号或密码错误!");
}
if (!user.getIsEnable()) {
return new ResponseResult(ResponseCode.FAILURE, "账号未激活,请联系管理员!");
}
String accessToken = getToken(loginPojo.getUsername(), loginPojo.getPassword());
result.put("access_token", accessToken);
result.put("userId", user.getUuid());
return new ResponseResult(ResponseCode.SUCCESS, result);
}
@Override
public ResponseResult logout(String accessToken) {
try {
OAuth2AccessToken oAuth2AccessToken = tokenStore.readAccessToken(accessToken);
tokenStore.removeAccessToken(oAuth2AccessToken);
return new ResponseResult(ResponseCode.SUCCESS);
} catch (Exception e) {
return new ResponseResult(ResponseCode.FAILURE);
}
}
@Override
public Map<String, String> refresh(String accessToken) {
Map<String, String> result = new HashMap<>();
//Access Token 不存在在直接返回null
String refreshToken = (String) redisTemplate.opsForValue().get(accessToken);
if (StrUtil.isBlank(refreshToken)) {
throw new BizException(ResponseCode.USER_NOT_LOGGED_IN);
}
//通过HTTP客户端请求登录接口
Map<String, Object> authParam = getAuthParam();
authParam.put("grant_type", "refresh_token");
authParam.put("refresh_token", refreshToken);
//获取access_token
String strJson = HttpUtil.post(accessTokenUri, authParam);
JSONObject jsonObject = JSONUtil.parseObj(strJson);
//新的access_token和refresh_token
String access_token = String.valueOf(jsonObject.get("access_token"));
String refresh_token = String.valueOf(jsonObject.get("refresh_token"));
if (StrUtil.isNotBlank(access_token) && StrUtil.isNotBlank(refreshToken)) {
//删除旧Token
redisTemplate.delete(accessToken);
//将refresh_token 保存到redis
redisTemplate.opsForValue().set(access_token, refresh_token);
result.put("access_token", access_token);
return result;
}
return null;
}
/**
* 获取用户token
*
* @param username 用户名
* @param password 密码
* @return String
*/
private String getToken(String username, String password) {
Map<String, String> result = new HashMap<>();
//通过HTTP客户端请求登录接口
Map<String, Object> authParam = getAuthParam();
authParam.put("username", username);
authParam.put("password", password);
authParam.put("grant_type", oauth2GrantType);
//获取access_token
String strJson = HttpUtil.post(accessTokenUri, authParam);
JSONObject jsonObject = JSONUtil.parseObj(strJson);
String accessToken = String.valueOf(jsonObject.get("access_token"));
String refreshToken = String.valueOf(jsonObject.get("refresh_token"));
if (StrUtil.isNotBlank(accessToken) && StrUtil.isNotBlank(refreshToken)) {
//将refresh_token保存在redis,设置超时时间为24小时
redisTemplate.opsForValue().set(accessToken, refreshToken, 24, TimeUnit.HOURS);
//将access_token返回
return accessToken;
}
return null;
}
private Map<String, Object> getAuthParam() {
Map<String, Object> param = new HashMap<>();
param.put("client_id", oauth2ClientId);
param.put("client_secret", oauth2ClientSecret);
return param;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
部分类没有列出来,请根据自己实际情况调整代码,核心代码都有注释
# 测试用户登录

# 注意
我的Demo项目中的接口权限地址配置在数据库中了,资源服务器可以动态获取可访问的资源url
数据库截图如下:

- ** 表示/test/路由下的所有接口都需要test权限才能访问