简介
json web token(缩写 jwt)是目前最流行的跨域认证解决方案。json web token 入门教程 这篇文章可以帮你了解jwt的概念。本文重点讲解spring boot 结合 jwt ,来实现前后端分离中,接口的安全调用。
spring security,这是一种基于 spring aop 和 servlet 过滤器的安全框架。它提供全面的安全性解决方案,同时在 web 请求级和方法调用级处理身份确认和授权。
快速上手
之前的文章已经对 spring security 进行了讲解,这一节对涉及到 spring security 的配置不详细讲解。若不了解 spring security 先移步到 spring boot security 详解。
建表
|
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
|
drop table if exists `user`;
drop table if exists `role`;
drop table if exists `user_role`;
drop table if exists `role_permission`;
drop table if exists `permission`;
create table `user` (
`id` bigint(11) not null auto_increment,
`username` varchar(255) not null,
`password` varchar(255) not null,
primary key (`id`)
);
create table `role` (
`id` bigint(11) not null auto_increment,
`name` varchar(255) not null,
primary key (`id`)
);
create table `user_role` (
`user_id` bigint(11) not null,
`role_id` bigint(11) not null
);
create table `role_permission` (
`role_id` bigint(11) not null,
`permission_id` bigint(11) not null
);
create table `permission` (
`id` bigint(11) not null auto_increment,
`url` varchar(255) not null,
`name` varchar(255) not null,
`description` varchar(255) null,
`pid` bigint(11) not null,
primary key (`id`)
);
insert into user (id, username, password) values (1,'user','e10adc3949ba59abbe56e057f20f883e');
insert into user (id, username , password) values (2,'admin','e10adc3949ba59abbe56e057f20f883e');
insert into role (id, name) values (1,'user');
insert into role (id, name) values (2,'admin');
insert into permission (id, url, name, pid) values (1,'/user/hi','',0);
insert into permission (id, url, name, pid) values (2,'/admin/hi','',0);
insert into user_role (user_id, role_id) values (1, 1);
insert into user_role (user_id, role_id) values (2, 1);
insert into user_role (user_id, role_id) values (2, 2);
insert into role_permission (role_id, permission_id) values (1, 1);
insert into role_permission (role_id, permission_id) values (2, 1);
insert into role_permission (role_id, permission_id) values (2, 2);
|
项目结构
|
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
|
resources
|___application.yml
java
|___com
| |____gf
| | |____springbootjwtapplication.java
| | |____config
| | | |____.ds_store
| | | |____securityconfig.java
| | | |____myfiltersecurityinterceptor.java
| | | |____myinvocationsecuritymetadatasourceservice.java
| | | |____myaccessdecisionmanager.java
| | |____entity
| | | |____user.java
| | | |____rolepermisson.java
| | | |____role.java
| | |____mapper
| | | |____permissionmapper.java
| | | |____usermapper.java
| | | |____rolemapper.java
| | |____utils
| | | |____jwttokenutil.java
| | |____controller
| | | |____authcontroller.java
| | |____filter
| | | |____jwttokenfilter.java
| | |____service
| | | |____impl
| | | | |____authserviceimpl.java
| | | | |____userdetailsserviceimpl.java
| | | |____authservice.java
|
关键代码
pom.xml
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
<dependency>
<groupid>org.springframework.boot</groupid>
<artifactid>spring-boot-starter-web</artifactid>
</dependency>
<dependency>
<groupid>org.springframework.boot</groupid>
<artifactid>spring-boot-starter-security</artifactid>
</dependency>
<dependency>
<groupid>io.jsonwebtoken</groupid>
<artifactid>jjwt</artifactid>
<version>0.9.0</version>
</dependency>
<dependency>
<groupid>mysql</groupid>
<artifactid>mysql-connector-java</artifactid>
<scope>runtime</scope>
</dependency>
<dependency>
<groupid>org.mybatis.spring.boot</groupid>
<artifactid>mybatis-spring-boot-starter</artifactid>
<version>2.0.0</version>
</dependency>
|
application.yml
|
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
|
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.driver
url: jdbc:mysql://localhost:3306/spring-security-jwt?useunicode=true&characterencoding=utf-8&usessl=false
username: root
password: root
securityconfig
@configuration
@enablewebsecurity
public class securityconfig extends websecurityconfigureradapter {
@autowired
private userdetailsservice userdetailsservice;
@autowired
public void configureglobal(authenticationmanagerbuilder auth) throws exception {
//校验用户
auth.userdetailsservice( userdetailsservice ).passwordencoder( new passwordencoder() {
//对密码进行加密
@override
public string encode(charsequence charsequence) {
system.out.println(charsequence.tostring());
return digestutils.md5digestashex(charsequence.tostring().getbytes());
}
//对密码进行判断匹配
@override
public boolean matches(charsequence charsequence, string s) {
string encode = digestutils.md5digestashex(charsequence.tostring().getbytes());
boolean res = s.equals( encode );
return res;
}
} );
}
@override
protected void configure(httpsecurity http) throws exception {
http.csrf().disable()
//因为使用jwt,所以不需要httpsession
.sessionmanagement().sessioncreationpolicy( sessioncreationpolicy.stateless).and()
.authorizerequests()
//options请求全部放行
.antmatchers( httpmethod.options, "/**").permitall()
//登录接口放行
.antmatchers("/auth/login").permitall()
//其他接口全部接受验证
.anyrequest().authenticated();
//使用自定义的 token过滤器 验证请求的token是否合法
http.addfilterbefore(authenticationtokenfilterbean(), usernamepasswordauthenticationfilter.class);
http.headers().cachecontrol();
}
@bean
public jwttokenfilter authenticationtokenfilterbean() throws exception {
return new jwttokenfilter();
}
@bean
@override
public authenticationmanager authenticationmanagerbean() throws exception {
return super.authenticationmanagerbean();
}
}
|
jwttokenutil
|
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
|
/**
* jwt 工具类
*/
@component
public class jwttokenutil implements serializable {
private static final string claim_key_username = "sub";
/**
* 5天(毫秒)
*/
private static final long expiration_time = 432000000;
/**
* jwt密码
*/
private static final string secret = "secret";
/**
* 签发jwt
*/
public string generatetoken(userdetails userdetails) {
map<string, object> claims = new hashmap<>(16);
claims.put( claim_key_username, userdetails.getusername() );
return jwts.builder()
.setclaims( claims )
.setexpiration( new date( instant.now().toepochmilli() + expiration_time ) )
.signwith( signaturealgorithm.hs512, secret )
.compact();
}
/**
* 验证jwt
*/
public boolean validatetoken(string token, userdetails userdetails) {
user user = (user) userdetails;
string username = getusernamefromtoken( token );
return (username.equals( user.getusername() ) && !istokenexpired( token ));
}
/**
* 获取token是否过期
*/
public boolean istokenexpired(string token) {
date expiration = getexpirationdatefromtoken( token );
return expiration.before( new date() );
}
/**
* 根据token获取username
*/
public string getusernamefromtoken(string token) {
string username = getclaimsfromtoken( token ).getsubject();
return username;
}
/**
* 获取token的过期时间
*/
public date getexpirationdatefromtoken(string token) {
date expiration = getclaimsfromtoken( token ).getexpiration();
return expiration;
}
/**
* 解析jwt
*/
private claims getclaimsfromtoken(string token) {
claims claims = jwts.parser()
.setsigningkey( secret )
.parseclaimsjws( token )
.getbody();
return claims;
}
}
|
jwttokenfilter
|
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
|
@component
public class jwttokenfilter extends onceperrequestfilter {
@autowired
private userdetailsservice userdetailsservice;
@autowired
private jwttokenutil jwttokenutil;
/**
* 存放token的header key
*/
public static final string header_string = "authorization";
@override
protected void dofilterinternal(httpservletrequest request, httpservletresponse response, filterchain chain) throws servletexception, ioexception {
string token = request.getheader( header_string );
if (null != token) {
string username = jwttokenutil.getusernamefromtoken(token);
if (username != null && securitycontextholder.getcontext().getauthentication() == null) {
userdetails userdetails = this.userdetailsservice.loaduserbyusername(username);
if (jwttokenutil.validatetoken(token, userdetails)) {
usernamepasswordauthenticationtoken authentication = new usernamepasswordauthenticationtoken(
userdetails, null, userdetails.getauthorities());
authentication.setdetails(new webauthenticationdetailssource().builddetails(
request));
securitycontextholder.getcontext().setauthentication(authentication);
}
}
}
chain.dofilter(request, response);
}
}
|
authserviceimpl
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
@service
public class authserviceimpl implements authservice {
@autowired
private authenticationmanager authenticationmanager;
@autowired
private userdetailsservice userdetailsservice;
@autowired
private jwttokenutil jwttokenutil;
@override
public string login(string username, string password) {
usernamepasswordauthenticationtoken uptoken = new usernamepasswordauthenticationtoken( username, password );
authentication authentication = authenticationmanager.authenticate(uptoken);
securitycontextholder.getcontext().setauthentication(authentication);
userdetails userdetails = userdetailsservice.loaduserbyusername( username );
string token = jwttokenutil.generatetoken(userdetails);
return token;
}
}
|
关键代码就是这些,其他类代码参照后面提供的源码地址。
验证
登录,获取token
curl -X POST -d "username=admin&password=123456" http://127.0.0.1:8080/auth/login
返回
eyjhbgcioijiuzuxmij9.eyjzdwiioijhzg1pbiisimv4cci6mtu1ndq1mzuwmx0.sglveqndgul9ph1op3lh9xrdzjis42vkbapd2npjt7e1tkhcey7aufixnzg9vc885_jtq4-h8r6yctrrjzl8fq
不带token访问资源
curl -X POST -d "name=zhangsan" http://127.0.0.1:8080/admin/hi
返回,拒绝访问
|
1
2
3
4
5
6
7
|
{
"timestamp": "2019-03-31t08:50:55.894+0000",
"status": 403,
"error": "forbidden",
"message": "access denied",
"path": "/auth/login"
}
|
携带token访问资源
|
1
|
curl -x post -h "authorization: eyjhbgcioijiuzuxmij9.eyjzdwiioijhzg1pbiisimv4cci6mtu1ndq1mzuwmx0.sglveqndgul9ph1op3lh9xrdzjis42vkbapd2npjt7e1tkhcey7aufixnzg9vc885_jtq4-h8r6yctrrjzl8fq" -d "name=zhangsan" http://127.0.0.1:8080/admin/hi
|
返回正确
|
1
|
hi zhangsan , you have 'admin' role
|
源码
https://github.com/gf-huanchupk/springbootlearning/tree/master/springboot-jwt
总结
以上所述是小编给大家介绍的spring boot security 结合 jwt 实现无状态的分布式api接口,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对快网idc网站的支持!
相关文章
- 64M VPS建站:能否支持高流量网站运行? 2025-06-10
- 64M VPS建站:怎样选择合适的域名和SSL证书? 2025-06-10
- 64M VPS建站:怎样优化以提高网站加载速度? 2025-06-10
- 64M VPS建站:是否适合初学者操作和管理? 2025-06-10
- ASP.NET自助建站系统中的用户注册和登录功能定制方法 2025-06-10
- 2025-07-10 怎样使用阿里云的安全工具进行服务器漏洞扫描和修复?
- 2025-07-10 怎样使用命令行工具优化Linux云服务器的Ping性能?
- 2025-07-10 怎样使用Xshell连接华为云服务器,实现高效远程管理?
- 2025-07-10 怎样利用云服务器D盘搭建稳定、高效的网站托管环境?
- 2025-07-10 怎样使用阿里云的安全组功能来增强服务器防火墙的安全性?
快网idc优惠网
QQ交流群
-
2025-05-25 11
-
2025-05-27 85
-
2025-06-05 59
-
2025-05-29 47
-
2025-05-25 45

