一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - Java教程 - Spring Boot Security 結合 JWT 實現無狀態的分布式API接口

Spring Boot Security 結合 JWT 實現無狀態的分布式API接口

2021-07-27 11:53幻楚 Java教程

JSON Web Token(縮寫 JWT)是目前最流行的跨域認證解決方案。這篇文章主要介紹了Spring Boot Security 結合 JWT 實現無狀態的分布式API接口 ,需要的朋友可以參考下

簡介

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接口,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對服務器之家網站的支持!

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 国产馆| 秋霞黄色网 | 国产精品欧美亚洲韩国日本99 | 久久中文骚妇内射 | 色综久久天天综合绕视看 | 国产精品一区三区 | 久久精品国产只有精品 | 小寡妇水真多好紧 | 婷婷综合久久中文字幕 | 好姑娘完整版在线观看中文 | 国产一区二区三区欧美精品 | 久久综合色超碰人人 | 91制片厂制作传媒破解版免费 | 国产精品日韩欧美一区二区 | 男人摸女人下面 | 海角社区在线登录 | 国产精品区牛牛影院 | 热久久99精品这里有精品 | 欧美黑人ⅹxxx片 | 穆挂英风流艳史小说 | 精品久久久久中文字幕日本 | 美女被吸乳得到大胸 | 男人女人性生活视频 | 国产日韩精品一区二区在线观看播放 | fuqer日本 | 欧美午夜寂寞影院安卓列表 | 青青草亚洲 | 欧美一区二区三区四区五区六区 | 九九精品免视频国产成人 | 精品视频 久久久 | 四虎播放器| 美女的隐私无遮挡撒尿 | 精品国产一级毛片大全 | 欧美日韩中文国产一区 | 女教师的一级毛片 | 人人揉人人爽五月天视频 | 日剧整部剧护妻狂魔免费观看全集 | 黑人开嫩苞 | 青青在线视频免费 | 99精品免费观看 | 午夜福利08550|