- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章spring boot+jwt实现api的token认证详解由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
前言 。
本篇和大家分享jwt(json web token)的使用,她主要用来生成接口访问的token和验证,其单独结合springboot来开发api接口token验证很是方便,由于jwt的token中存储有用户的信息并且有加密,所以适用于分布式,这样直接吧信息存储在用户本地减速了服务端存储sessiion或token的压力; 。
如下快速使用:
1
2
3
4
5
6
7
8
9
10
11
12
|
<!--jwt-->
<dependency>
<groupid>io.jsonwebtoken</groupid>
<artifactid>jjwt</artifactid>
<version>
0.9
.
0
</version>
</dependency>
<!--阿里 fastjson依赖-->
<dependency>
<groupid>com.alibaba</groupid>
<artifactid>fastjson</artifactid>
<version>
1.2
.
44
</version>
</dependency>
|
一般使用jwt来达到3种结果:
生成token 。
引入了jjwt依赖后,要生成token很方便;对于一个token来说,代表的是唯一并且不可逆的,因此我们在生成时需要增加一些唯一数据进去,比如下面的id:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
long
currenttime = system.currenttimemillis();
return
jwts.builder()
.setid(uuid.randomuuid().tostring())
.setissuedat(
new
date(currenttime))
//签发时间
.setsubject(
"system"
)
//说明
.setissuer(
"shenniu003"
)
//签发者信息
.setaudience(
"custom"
)
//接收用户
.compresswith(compressioncodecs.gzip)
//数据压缩方式
.signwith(signaturealgorithm.hs256, encrykey)
//加密方式
.setexpiration(
new
date(currenttime + secondtimeout *
1000
))
//过期时间戳
.addclaims(claimmaps)
//cla信息
.compact();
|
通过uuid来标记唯一id信息;当然在对token加密时需要用到秘钥,jwt很是方便她支持了很多中加密方式如:hs256,hs265,md5等复杂及常用的加密方式; 。
jwt生成的token中内容分为3个部分:head信息,payload信息,sign信息,通常我们要做的是往payload增加一些用户信息(比如:账号,昵称,权限等,但不包含密码);在对jwt的token有一定了解后,我们来看下真实生成的token值:
1
|
eyjhbgcioijiuzi1niisinppcci6ikdasvaifq.h4siaaaaaaaaafwmtq7cibse7_lwkpdzaesp4qnyinciptx4ine0vbtg4sllfppn7hatgwbwg1bkl4grcbeciwpujzf8iiepjxfapaag2reypuecr2vxyed13nb0pplw3hp1eenblqsquiffy0ohurl3i70evweu_afsejzhd7dlcdv5ntmyhuilhtd3rf_hacchrtv--7yaaaa.i4xwoqtawi0-dwhwn8uz4dbm-vfli5bavyu9lryxu5e
|
验证token是否有效 。
token生成的时都会伴随者有一个失效的时间,在这我们可以通过setexpiration函数设置过期时间,记住jwt的有效时间不是滑动的,也就是说不做任何处理时,当到达第一次设置的失效时间时,就基本没用了,要获取token是否过期可以使用如下方式:
1
2
3
4
5
6
7
8
9
|
public
static
boolean
isexpiration(string token, string encrykey) {
try
{
return
getclaimsbody(token, encrykey)
.getexpiration()
.before(
new
date());
}
catch
(expiredjwtexception ex) {
return
true
;
}
}
|
这里使用了date的before来用获取的过期时间和当前时间对比,判断是否继续有效,需要注意的是如果在token失效后再通过getclaimsbody(token, encrykey)获取信息,此时会报expiredjwtexception错误,我们即可认为过期.
获取token中jwt信息(主要用户信息) 。
通常我们要把登录用户信息存储在jwt生成的token中,这里可以通过 addclaims(claimmaps) 传递map来设置信息,反过来要获取token中的用户信息,我们需要这样做:
1
2
3
4
|
return
jwts.parser()
.setsigningkey(encrykey)
.parseclaimsjws(token)
.getbody();
|
此时body获取出来是claims类型,我们需要从中获取到用户信息,需要注意的是在addclaims存储信息的时候如果存储的map值没做过出来,那完整的实体对象存储进去后会映射成一个linkhasmap类型,如下:
因此通常会在存储的时候json化,如下代码:
1
2
3
|
claimmaps.foreach((key, val) -> {
claimmaps.put(key, json.tojsonstring(val));
});
|
再来就是通过get方法获取我们存储进去的信息,并json反序列化:
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
|
/**
* 获取body某个值
*
* @param token
* @param encrykey
* @param key
* @return
*/
public
static
object getval(string token, string encrykey, string key) {
return
getjws(token, encrykey).getbody().get(key);
}
/**
* 获取body某个值,json字符转实体
*
* @param token
* @param encrykey
* @param key
* @param tclass
* @param <t>
* @return
*/
public
static
<t> t getvalbyt(string token, string encrykey, string key,
class
<t> tclass) {
try
{
string strjson = getval(token, encrykey, key).tostring();
return
json.parseobject(strjson, tclass);
}
catch
(exception ex) {
return
null
;
}
}
|
来到这里一个jwt的util代码基本就完成了,下面给出完整的代码例子,仅供参考:
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
|
public
class
jwtutil {
/**
* 获取token - json化 map信息
*
* @param claimmaps
* @param encrykey
* @param secondtimeout
* @return
*/
public
static
string gettokenbyjson(map<string, object> claimmaps, string encrykey,
int
secondtimeout) {
return
gettoken(claimmaps,
true
, encrykey, secondtimeout);
}
/**
* 获取token
*
* @param claimmaps
* @param isjsonmpas
* @param encrykey
* @param secondtimeout
* @return
*/
public
static
string gettoken(map<string, object> claimmaps,
boolean
isjsonmpas, string encrykey,
int
secondtimeout) {
if
(isjsonmpas) {
claimmaps.foreach((key, val) -> {
claimmaps.put(key, json.tojsonstring(val));
});
}
long
currenttime = system.currenttimemillis();
return
jwts.builder()
.setid(uuid.randomuuid().tostring())
.setissuedat(
new
date(currenttime))
//签发时间
.setsubject(
"system"
)
//说明
.setissuer(
"shenniu003"
)
//签发者信息
.setaudience(
"custom"
)
//接收用户
.compresswith(compressioncodecs.gzip)
//数据压缩方式
.signwith(signaturealgorithm.hs256, encrykey)
//加密方式
.setexpiration(
new
date(currenttime + secondtimeout *
1000
))
//过期时间戳
.addclaims(claimmaps)
//cla信息
.compact();
}
/**
* 获取token中的claims信息
*
* @param token
* @param encrykey
* @return
*/
private
static
jws<claims> getjws(string token, string encrykey) {
return
jwts.parser()
.setsigningkey(encrykey)
.parseclaimsjws(token);
}
public
static
string getsignature(string token, string encrykey) {
try
{
return
getjws(token, encrykey).getsignature();
}
catch
(exception ex) {
return
""
;
}
}
/**
* 获取token中head信息
*
* @param token
* @param encrykey
* @return
*/
public
static
jwsheader getheader(string token, string encrykey) {
try
{
return
getjws(token, encrykey).getheader();
}
catch
(exception ex) {
return
null
;
}
}
/**
* 获取payload body信息
*
* @param token
* @param encrykey
* @return
*/
public
static
claims getclaimsbody(string token, string encrykey) {
return
getjws(token, encrykey).getbody();
}
/**
* 获取body某个值
*
* @param token
* @param encrykey
* @param key
* @return
*/
public
static
object getval(string token, string encrykey, string key) {
return
getjws(token, encrykey).getbody().get(key);
}
/**
* 获取body某个值,json字符转实体
*
* @param token
* @param encrykey
* @param key
* @param tclass
* @param <t>
* @return
*/
public
static
<t> t getvalbyt(string token, string encrykey, string key,
class
<t> tclass) {
try
{
string strjson = getval(token, encrykey, key).tostring();
return
json.parseobject(strjson, tclass);
}
catch
(exception ex) {
return
null
;
}
}
/**
* 是否过期
*
* @param token
* @param encrykey
* @return
*/
public
static
boolean
isexpiration(string token, string encrykey) {
try
{
return
getclaimsbody(token, encrykey)
.getexpiration()
.before(
new
date());
}
catch
(expiredjwtexception ex) {
return
true
;
}
}
public
static
string getsubject(string token, string encrykey) {
try
{
return
getclaimsbody(token, encrykey).getsubject();
}
catch
(exception ex) {
return
""
;
}
}
}
|
过滤器验证token 。
有了基本的jwtutil工具,我们需要用到springboot项目中,一般来说对于登录授权token验证可以通过过滤器来操作,这里创建一个authenfilter,用于对post请求过来的token做验证:
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
|
public
class
authenfilter
implements
filter {
@override
public
void
dofilter(servletrequest servletrequest, servletresponse servletresponse, filterchain filterchain)
throws
ioexception, servletexception {
httpservletrequest rq = (httpservletrequest) servletrequest;
httpservletresponse rp = (httpservletresponse) servletresponse;
rpbase rpbase =
new
rpbase();
try
{
//只接受post
if
(!rq.getmethod().equalsignorecase(
"post"
)) {
filterchain.dofilter(servletrequest, servletresponse);
return
;
}
string token = rq.getheader(
"token"
);
if
(stringutils.isempty(token)) {
rpbase.setmsg(
"无token"
);
return
;
}
//jwt验证
mouser mouser = jwtutil.getvalbyt(token, webconfig.token_encrykey, webconfig.login_user, mouser.
class
);
if
(mouser ==
null
) {
rpbase.setmsg(
"token已失效"
);
return
;
}
system.out.println(
"token用户:"
+ mouser.getnickname());
filterchain.dofilter(servletrequest, servletresponse);
}
catch
(exception ex) {
}
finally
{
if
(!stringutils.isempty(rpbase.getmsg())) {
rp.setcharacterencoding(
"utf-8"
);
rpbase.setcode(httpstatus.bad_request.value());
rp.getwriter().write(json.tojsonstring(rpbase));
}
}
}
}
|
要是自定义过滤器authenfilter生效,还需要把她注册到容器中,这里通过编码方式,当然还可以通过@webfilter注解来加入到容器中:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
@configuration
public
class
webfilterconfig {
@bean
public
filterregistrationbean setfilter() {
filterregistrationbean registrationbean =
new
filterregistrationbean();
registrationbean.setfilter(
new
authenfilter());
registrationbean.addurlpatterns(
"/api/*"
);
registrationbean.setorder(filterregistrationbean.lowest_precedence);
return
registrationbean;
}
}
|
注意addurlpatterns匹配的是过滤器作用的url连接,根据需求而定;为了验证效果,这里我创建了两个接口gettoken和t0,分别是获取token和post查询接口,代码如是:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
@restcontroller
public
class
testcontroller {
@postmapping
(
"/api/t0"
)
public
string t0()
throws
myexception {
return
uuid.randomuuid().tostring();
}
@getmapping
(
"/token/{username}"
)
public
string gettoken(
@pathvariable
string username) {
mouser mouser =
new
mouser();
mouser.setusername(username);
mouser.setnickname(username);
map<string, object> map =
new
hashmap<>();
map.put(webconfig.login_user, mouser);
return
jwtutil.gettokenbyjson(map,
webconfig.token_encrykey,
webconfig.token_secondtimeout);
}
}
|
最终要获通过head传递token值来访问t01接口,得到如下结果:
token在有效时间后访问直接失败,从新获取token并访问t01接口,得到成功的信息:
git地址: https://github.com/shenniubuxing3 。
总结 。
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对我的支持.
原文链接:https://www.cnblogs.com/wangrudong003/p/10122706.html 。
最后此篇关于spring boot+jwt实现api的token认证详解的文章就讲到这里了,如果你想了解更多关于spring boot+jwt实现api的token认证详解的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
有人可以解释一下 spring-boot-parent 和 spring-boot-starter-parent 之间的区别吗,正如我在下面附加的 GIT HUB 代码链接之一中看到的,他们为 spr
我有与 jersey 框架集成的 Spring Boot 应用程序。 现在,当我尝试运行该应用程序时,它只是停留在 Spring 启动徽标上,之后没有任何 react 。 我也尝试添加 -X ,但徽标
我指的是 Spring Boot 关于 的文档自动配置 和 执行器 模块: 自动配置: Spring Boot AutoConfiguration attempts to automatically
我正在尝试将 apache log4j 集成到我的 Spring boot 应用程序中。这是我的 build.gradle 文件: build.gradle buildscript { rep
使用 Spring Boot Maven 插件的以下命令在生产中启动 Spring Boot 应用程序是否是一个好主意或实践? mvn spring-boot:run 最佳答案 不,这是个坏主意。 您
据我所知,spring boot 和 spring session 为我们提供了一站式自动配置,但是当我的应用程序使用 session redis 和应用程序缓存 redis 时,不是同一个 redi
我希望使用Spring Boot创建一个新的Web应用程序。不幸的是,我的服务器在技术堆栈方面相当有限。它安装了Java 5。 谁能告诉我spring boot是否可以在Java 1.5上运行以及什么
我有3个实体 CarWash(设置Wash) Wash(car_wash_id FK到CarWash) WashComment(wash_id FK到Wash) 有什么办法可以写这个查询 @Qu
我一直在关注this文章。 我正在尝试在Spring-boot应用程序中优雅地处理gRPC错误,的主要目标是能够在gRPC客户端中获取错误状态。 在上面的文章之后,我坚持为异常添加拦截器。如何在Spr
我有一个要使用的自定义log4j布局插件。在IntelliJ中运行或与./gradlew bootRun一起运行时,插件可以正常工作。不使用./gradlew bootJar构建启动jar。 启用-D
我想在给定范围 (5001-5100) 的随机端口上启动 Spring Cloud 应用程序(Spring Boot 1.5.14,Spring Cloud Edgware.SR4)。我知道我们可以使
任何人都可以向我展示或指出不使用 spring boot gradle 插件的 spring boot gradle 项目。 我正在寻找类似不使用 gradle 插件的 spring boot sta
我当时尝试包含上述依赖项之一,但找不到任何区别: spring boot starter web:我可以看到 Flux 和 Mono 类并制作一个响应式(Reactive)休息 Controller
我们一直在为我们的应用程序使用 Springboot 1.X。 现在准备开始一些新的应用程序,想知道我们是应该使用 SpringBoot2.0 还是坚持使用 SpringBoot 1.X? 对一种方式
我希望记录应用程序正在加载 application-profile.propeties 或 application.yml。怎么做。在哪种方法中,我可以听取它并检测它是成功加载还是失败。 最佳答案 您
当我在 pom.xml 中添加简单的 spring-boot-starter-data-jpa 依赖项时,在 pom.xml 文件中出现错误。如果我删除该依赖项,则不会再有错误。我不确定为什么会发生这
我希望记录应用程序正在加载 application-profile.propeties 或 application.yml。怎么做。在哪种方法中,我可以听取它并检测它是成功加载还是失败。 最佳答案 您
我在网上看了很多关于 spring-boot-devtools 的文章和问题,但仍然无法弄清楚为什么它对我不起作用。每次运行我的应用程序时,我都会得到以下信息: 17:54:28.057 [main]
我正在尝试将现有的 Spring 应用程序移植到 Spring Boot。我不使用 spring-boot-starter-data-solr 启动器,但是我的类路径上有 apache solrj (
(这主要是一个历史问题。Pivotal 建议所有论坛讨论都在 StackOverflow 上进行,这就是我在这里问它的原因。) Spring Boot 项目用来证明将应用程序的类和依赖项从可执行 ja
我是一名优秀的程序员,十分优秀!