激情久久久_欧美视频区_成人av免费_不卡视频一二三区_欧美精品在欧美一区二区少妇_欧美一区二区三区的

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

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

服務器之家 - 編程語言 - Java教程 - Spring-boot結合Shrio實現JWT的方法

Spring-boot結合Shrio實現JWT的方法

2021-04-26 15:08workabee Java教程

這篇文章主要介紹了Spring-boot結合Shrio實現JWT的方法,小編覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧

本文介紹了spring-boot結合shrio實現jwt的方法,分享給大家,具體如下:

關于驗證大致分為兩個方面:

  1. 用戶登錄時的驗證;
  2. 用戶登錄后每次訪問時的權限認證

主要解決方法:使用自定義的shiro filter

項目搭建:

這是一個spring-boot 的web項目,不了解spring-boot的項目搭建,請google。

pom.mx引入相關jar包

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<!-- shiro 權限管理 -->
 <dependency>
   <groupid>org.apache.shiro</groupid>
   <artifactid>shiro-spring</artifactid>
   <version>${shiro.version}</version>
 </dependency>
 <dependency>
   <groupid>org.apache.shiro</groupid>
   <artifactid>shiro-core</artifactid>
   <version>${shiro.version}</version>
 </dependency>
<!-- jwt -->
  <dependency>
   <groupid>io.jsonwebtoken</groupid>
   <artifactid>jjwt</artifactid>
   <version>0.9.0</version>
 </dependency>

shrio 的相關配置

劃重點!!自定義了一個filter

?
1
filtermap.put("jwtfilter", new jwtfilter());
?
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
@configuration
public class shiroconfig {
  @bean
  public shirofilterfactorybean getshirofilterfactorybean(securitymanager securitymanager) {
    shirofilterfactorybean shirofilterfactorybean = new shirofilterfactorybean();
    shirofilterfactorybean.setsecuritymanager(securitymanager);
    // 添加自己的過濾器并且取名為jwtfilter
    map<string, filter> filtermap = new hashmap<>();
    filtermap.put("jwtfilter", new jwtfilter());
    shirofilterfactorybean.setfilters(filtermap);
    /*
     * 自定義url規則
     * http://shiro.apache.org/web.html#urls-
     */
    map<string, string> filterchaindefinitionmap = shirofilterfactorybean.getfilterchaindefinitionmap();
    filterchaindefinitionmap.put("/**", "jwtfilter");
    shirofilterfactorybean.setfilterchaindefinitionmap(filterchaindefinitionmap);
    return shirofilterfactorybean;
  }
 
 
  /**
   * securitymanager 不用直接注入shirodbrealm,可能會導致事務失效
   * 解決方法見 handlecontextrefresh
   * http://www.debugrun.com/a/nks9ejq.html
   */
  @bean("securitymanager")
  public defaultwebsecuritymanager securitymanager(tokenrealm tokenrealm) {
    defaultwebsecuritymanager manager = new defaultwebsecuritymanager();
    manager.setrealm(tokenrealm);
    /*
     * 關閉shiro自帶的session,詳情見文檔
     * http://shiro.apache.org/session-management.html#sessionmanagement-statelessapplications%28sessionless%29
     */
    defaultsubjectdao subjectdao = new defaultsubjectdao();
    defaultsessionstorageevaluator defaultsessionstorageevaluator = new defaultsessionstorageevaluator();
    defaultsessionstorageevaluator.setsessionstorageenabled(false);
    subjectdao.setsessionstorageevaluator(defaultsessionstorageevaluator);
    manager.setsubjectdao(subjectdao);
    return manager;
  }
 
  @bean
  public lifecyclebeanpostprocessor lifecyclebeanpostprocessor() {
    return new lifecyclebeanpostprocessor();
  }
 
  @bean(name = "tokenrealm")
  @dependson("lifecyclebeanpostprocessor")
  public tokenrealm tokenrealm() {
    return new tokenrealm();
  }
 
  @bean
  @dependson("lifecyclebeanpostprocessor")
  public defaultadvisorautoproxycreator defaultadvisorautoproxycreator() {
    defaultadvisorautoproxycreator defaultadvisorautoproxycreator = new defaultadvisorautoproxycreator();
    // 強制使用cglib,防止重復代理和可能引起代理出錯的問題
    // https://zhuanlan.zhihu.com/p/29161098
    defaultadvisorautoproxycreator.setproxytargetclass(true);
    return defaultadvisorautoproxycreator;
  }
 
  @bean
  public authorizationattributesourceadvisor getauthorizationattributesourceadvisor(securitymanager securitymanager) {
    authorizationattributesourceadvisor authorizationattributesourceadvisor = new authorizationattributesourceadvisor();
    authorizationattributesourceadvisor.setsecuritymanager(securitymanager);
    return new authorizationattributesourceadvisor();
  }
}

自定義shrio filter

執行順序:prehandle -> dofilterinternal -> executelogin -> onloginsuccess

主要判斷是不是登錄請求的是 dofilterinternal

?
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
public class jwtfilter extends basichttpauthenticationfilter {
  /**
   * 自定義執行登錄的方法
   */
  @override
  protected boolean executelogin(servletrequest request, servletresponse response) throws ioexception {
    httpservletrequest httpservletrequest = (httpservletrequest) request;
    usernamepasswordtoken usernamepasswordtoken = json.parseobject(httpservletrequest.getinputstream(), usernamepasswordtoken.class);
    // 提交給realm進行登入,如果錯誤他會拋出異常并被捕獲
    subject subject = this.getsubject(request, response);
    subject.login(usernamepasswordtoken);
    return this.onloginsuccess(usernamepasswordtoken, subject, request, response);
    //錯誤拋出異常
  }
 
  /**
   * 最先執行的方法
   */
  @override
  protected boolean prehandle(servletrequest request, servletresponse response) throws exception {
    return super.prehandle(request, response);
  }
 
  /**
   * 登錄成功后登錄的操作
   * 加上jwt 的header
   */
  @override
  protected boolean onloginsuccess(authenticationtoken token, subject subject, servletrequest request, servletresponse response) {
    httpservletresponse httpservletresponse = (httpservletresponse) response;
    string jwttoken = jwts.builder()
        .setid(token.getprincipal().tostring())
        .setexpiration(datetime.now().plusminutes(30).todate())
        .signwith(signaturealgorithm.hs256, jwtcost.signaturekey)
        .compact();
    httpservletresponse.addheader(authorization_header, jwttoken);
    return true;
  }
 
  /**
   * 登錄以及校驗的主要流程
   * 判斷是否是登錄,或者是登陸后普通的一次請求
   */
  @override
  public void dofilterinternal(servletrequest servletrequest, servletresponse servletresponse, filterchain filterchain) throws ioexception, servletexception {
    httpservletrequest httpservletrequest = (httpservletrequest) servletrequest;
    httpservletresponse httpservletresponse = (httpservletresponse) servletresponse;
    string servletpath = httpservletrequest.getservletpath();
    if (stringutils.equals(servletpath, "/login")) {
      //執行登錄
      this.executelogin(servletrequest, servletresponse);
    } else {
      string authenticationheader = httpservletrequest.getheader(authorization_header);
      if (stringutils.isnotempty(authenticationheader)) {
 
        claims body = jwts.parser()
            .setsigningkey(jwtcost.signaturekey)
            .parseclaimsjws(authenticationheader)
            .getbody();
        if (body != null) {
          //更新token
          body.setexpiration(datetime.now().plusminutes(30).todate());
          string updatetoken = jwts.builder().setclaims(body).compact();
          httpservletresponse.addheader(authorization_header, updatetoken);
 
          //添加用戶憑證
          principalcollection principals = new simpleprincipalcollection(body.getid(), jwtcost.usernamepasswordrealm);//拼裝shiro用戶信息
          websubject.builder builder = new websubject.builder(servletrequest, servletresponse);
          builder.principals(principals);
          builder.authenticated(true);
          builder.sessioncreationenabled(false);
          websubject subject = builder.buildwebsubject();
          //塞入容器,統一調用
          threadcontext.bind(subject);
          filterchain.dofilter(httpservletrequest, httpservletresponse);
        }
      } else {
        httpservletresponse.setstatus(httpstatus.forbidden.value());
      }
    }
  }
}

登錄失敗處理

處理shrio異常

?
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
@restcontrolleradvice
public class globalcontrollerexceptionhandler {
  @exceptionhandler(value = exception.class)
  public object allexceptionhandler(httpservletrequest request, httpservletresponse response, exception exception) {
    string message = exception.getcause().getmessage();
    logutil.error(message);
    return new resultinfo(exception.getclass().getname(), message);
  }
 
  /*=========== shiro 異常攔截==============*/
 
  @exceptionhandler(value = incorrectcredentialsexception.class)
  public string incorrectcredentialsexception(httpservletrequest request, httpservletresponse response, exception exception) {
    response.setstatus(httpstatus.forbidden.value());
    return "incorrectcredentialsexception";
  }
 
  @exceptionhandler(value = unknownaccountexception.class)
  public string unknownaccountexception(httpservletrequest request, httpservletresponse response, exception exception) {
    response.setstatus(httpstatus.forbidden.value());
    return "unknownaccountexception";
  }
 
  @exceptionhandler(value = lockedaccountexception.class)
  public string lockedaccountexception(httpservletrequest request, httpservletresponse response, exception exception) {
    response.setstatus(httpstatus.forbidden.value());
    return "lockedaccountexception";
  }
 
  @exceptionhandler(value = excessiveattemptsexception.class)
  public string excessiveattemptsexception(httpservletrequest request, httpservletresponse response, exception exception) {
    response.setstatus(httpstatus.forbidden.value());
    return "excessiveattemptsexception";
  }
 
  @exceptionhandler(value = authenticationexception.class)
  public string authenticationexception(httpservletrequest request, httpservletresponse response, exception exception) {
    response.setstatus(httpstatus.forbidden.value());
    return "authenticationexception";
  }
 
  @exceptionhandler(value = unauthorizedexception.class)
  public string unauthorizedexception(httpservletrequest request, httpservletresponse response, exception exception) {
    response.setstatus(httpstatus.forbidden.value());
    return "unauthorizedexception";
  }
}

處理jwt異常

這是個坑,因為是在filter內發生的異常,@exceptionhandler是截獲不到的。

?
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
/**
 * 截獲spring boot error頁面
 */
@restcontroller
public class globalexceptionhandler implements errorcontroller {
  @override
  public string geterrorpath() {
    return "/error";
  }
 
  @requestmapping(value = "/error")
  public object error(httpservletrequest request, httpservletresponse response) throws exception {
    // 錯誤處理邏輯
    exception exception = (exception) request.getattribute("javax.servlet.error.exception");
    throwable cause = exception.getcause();
    if (cause instanceof expiredjwtexception) {
      response.setstatus(httpstatus.gateway_timeout.value());
      return new resultinfo("expiredjwtexception", cause.getmessage());
    }
    if (cause instanceof malformedjwtexception) {
      response.setstatus(httpstatus.forbidden.value());
      return new resultinfo("malformedjwtexception", cause.getmessage());
    }
    return new resultinfo(cause.getcause().getmessage(), cause.getmessage());
  }
}

關于權限等授權信息,可以直接放到redis中實現緩存。我認為也是不錯的。

源碼奉上:githup-shiro分支 :溫馨提示:平時測試代碼可能比較亂。

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持服務器之家。

原文鏈接:https://segmentfault.com/a/1190000014750168

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 成人444kkkk在线观看 | 成人区精品一区二区婷婷 | 成人精品久久 | 在线日韩av电影 | 国产一区国产二区在线观看 | 色中色在线播放 | 海外中文字幕在线观看 | 欧美成人免费一区二区三区 | 国产精品一区在线看 | 免费国产成人高清在线看软件 | 天堂成人国产精品一区 | 午夜精品久久久久久中宇 | 免费久久久 | 久在线观看福利视频69 | 欧美精品免费一区二区三区 | 狼伊千合综网中文 | 国产在线免 | 日韩av毛片免费观看 | 欧美性受xxxx白人性爽 | 在线播放免费播放av片 | 亚卅毛片| 成人三区四区 | 欧美日韩色 | 久久精品国产99国产精品亚洲 | 成人毛片视频在线观看 | 黄色片网站在线免费观看 | 国产精品久久99精品毛片三a | 中文字幕精品在线观看 | 亚洲免费看片网站 | 亚洲一区二区三区在线看 | 久久精品一二三区白丝高潮 | 一区二区免费 | 久久国产精品电影 | 国产日韩成人 | 免看黄大片aa | 欧美1区2区在线观看 | 久色婷婷| 日本在线播放一区 | 久久毛片免费 | 国产乱淫a∨片免费观看 | 国产精品99久久久久久久 |