详解Spring Boot实战之Filter实现使用JWT进行接口认证

时间:2022-09-03 00:14:09

本文介绍了spring boot实战之filter实现使用jwt进行接口认证,分享给大家

jwt(json web token)

用户发送按照约定,向服务端发送 header、payload 和 signature,并包含认证信息(密码),验证通过后服务端返回一个token,之后用户使用该token作为登录凭证,适合于移动端和api

jwt使用流程

详解Spring Boot实战之Filter实现使用JWT进行接口认证

本文示例接上面几篇文章中的代码进行编写,请阅读本文的同时可以参考前面几篇文章

1、添加依赖库jjwt,本文中构造jwt及解析jwt都使用了jjwt库

?
1
2
3
4
5
<dependency>
  <groupid>io.jsonwebtoken</groupid>
  <artifactid>jjwt</artifactid>
  <version>0.6.0</version>
</dependency>

2、添加登录获取token时,所需要的认证信息类loginpara.java

?
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
package com.xiaofangtech.sunt.jwt;
 
public class loginpara {
  private string clientid;
  private string username;
  private string password;
  private string captchacode;
  private string captchavalue;
   
  public string getclientid() {
    return clientid;
  }
  public void setclientid(string clientid) {
    this.clientid = clientid;
  }
  public string getusername() {
    return username;
  }
  public void setusername(string username) {
    this.username = username;
  }
  public string getpassword() {
    return password;
  }
  public void setpassword(string password) {
    this.password = password;
  }
  public string getcaptchacode() {
    return captchacode;
  }
  public void setcaptchacode(string captchacode) {
    this.captchacode = captchacode;
  }
  public string getcaptchavalue() {
    return captchavalue;
  }
  public void setcaptchavalue(string captchavalue) {
    this.captchavalue = captchavalue;
  }
}

3、添加构造jwt及解析jwt的帮助类jwthelper.java

?
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
package com.xiaofangtech.sunt.jwt;
 
import java.security.key;
import java.util.date;
 
import javax.crypto.spec.secretkeyspec;
import javax.xml.bind.datatypeconverter;
 
import io.jsonwebtoken.claims;
import io.jsonwebtoken.jwtbuilder;
import io.jsonwebtoken.jwts;
import io.jsonwebtoken.signaturealgorithm;
 
public class jwthelper {
  public static claims parsejwt(string jsonwebtoken, string base64security){
    try
    {
      claims claims = jwts.parser()
            .setsigningkey(datatypeconverter.parsebase64binary(base64security))
            .parseclaimsjws(jsonwebtoken).getbody();
      return claims;
    }
    catch(exception ex)
    {
      return null;
    }
  }
   
  public static string createjwt(string name, string userid, string role, 
      string audience, string issuer, long ttlmillis, string base64security) 
  {
    signaturealgorithm signaturealgorithm = signaturealgorithm.hs256;
      
    long nowmillis = system.currenttimemillis();
    date now = new date(nowmillis);
      
    //生成签名密钥
    byte[] apikeysecretbytes = datatypeconverter.parsebase64binary(base64security);
    key signingkey = new secretkeyspec(apikeysecretbytes, signaturealgorithm.getjcaname());
      
     //添加构成jwt的参数
    jwtbuilder builder = jwts.builder().setheaderparam("typ", "jwt")
                    .claim("role", role)
                    .claim("unique_name", name)
                    .claim("userid", userid)
                    .setissuer(issuer)
                    .setaudience(audience)
                    .signwith(signaturealgorithm, signingkey);
     //添加token过期时间
    if (ttlmillis >= 0) {
      long expmillis = nowmillis + ttlmillis;
      date exp = new date(expmillis);
      builder.setexpiration(exp).setnotbefore(now);
    }
      
     //生成jwt
    return builder.compact();
  
}

4、添加token返回结果类accesstoken.java

?
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
package com.xiaofangtech.sunt.jwt;
 
public class accesstoken {
  private string access_token;
  private string token_type;
  private long expires_in;
  public string getaccess_token() {
    return access_token;
  }
  public void setaccess_token(string access_token) {
    this.access_token = access_token;
  }
  public string gettoken_type() {
    return token_type;
  }
  public void settoken_type(string token_type) {
    this.token_type = token_type;
  }
  public long getexpires_in() {
    return expires_in;
  }
  public void setexpires_in(long expires_in) {
    this.expires_in = expires_in;
  }
}

5、添加获取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
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
package com.xiaofangtech.sunt.jwt;
 
import org.springframework.beans.factory.annotation.autowired;
import org.springframework.web.bind.annotation.requestbody;
import org.springframework.web.bind.annotation.requestmapping;
import org.springframework.web.bind.annotation.restcontroller;
 
import com.xiaofangtech.sunt.bean.userinfo;
import com.xiaofangtech.sunt.repository.userinforepository;
import com.xiaofangtech.sunt.utils.myutils;
import com.xiaofangtech.sunt.utils.resultmsg;
import com.xiaofangtech.sunt.utils.resultstatuscode;
 
@restcontroller
public class jsonwebtoken {
  @autowired
  private userinforepository userrepositoy;
   
  @autowired
  private audience audienceentity;
   
  @requestmapping("oauth/token")
  public object getaccesstoken(@requestbody loginpara loginpara)
  {
    resultmsg resultmsg;
    try
    {
      if(loginpara.getclientid() == null
          || (loginpara.getclientid().compareto(audienceentity.getclientid()) != 0))
      {
        resultmsg = new resultmsg(resultstatuscode.invalid_clientid.geterrcode(), 
            resultstatuscode.invalid_clientid.geterrmsg(), null);
        return resultmsg;
      }
       
      //验证码校验在后面章节添加
       
       
      //验证用户名密码
      userinfo user = userrepositoy.finduserinfobyname(loginpara.getusername());
      if (user == null)
      {
        resultmsg = new resultmsg(resultstatuscode.invalid_password.geterrcode(),
            resultstatuscode.invalid_password.geterrmsg(), null);
        return resultmsg;
      }
      else
      {
        string md5password = myutils.getmd5(loginpara.getpassword()+user.getsalt());
         
        if (md5password.compareto(user.getpassword()) != 0)
        {
          resultmsg = new resultmsg(resultstatuscode.invalid_password.geterrcode(),
              resultstatuscode.invalid_password.geterrmsg(), null);
          return resultmsg;
        }
      }
       
      //拼装accesstoken
      string accesstoken = jwthelper.createjwt(loginpara.getusername(), string.valueof(user.getname()),
          user.getrole(), audienceentity.getclientid(), audienceentity.getname(),
          audienceentity.getexpiressecond() * 1000, audienceentity.getbase64secret());
       
      //返回accesstoken
      accesstoken accesstokenentity = new accesstoken();
      accesstokenentity.setaccess_token(accesstoken);
      accesstokenentity.setexpires_in(audienceentity.getexpiressecond());
      accesstokenentity.settoken_type("bearer");
      resultmsg = new resultmsg(resultstatuscode.ok.geterrcode(), 
          resultstatuscode.ok.geterrmsg(), accesstokenentity);
      return resultmsg;
       
    }
    catch(exception ex)
    {
      resultmsg = new resultmsg(resultstatuscode.system_err.geterrcode(), 
          resultstatuscode.system_err.geterrmsg(), null);
      return resultmsg;
    }
  }
}

6、添加使用jwt认证的filter

?
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
package com.xiaofangtech.sunt.filter;
 
import java.io.ioexception;
 
import javax.servlet.filter;
import javax.servlet.filterchain;
import javax.servlet.filterconfig;
import javax.servlet.servletexception;
import javax.servlet.servletrequest;
import javax.servlet.servletresponse;
import javax.servlet.http.httpservletrequest;
import javax.servlet.http.httpservletresponse;
 
import org.springframework.beans.factory.annotation.autowired;
import org.springframework.web.context.support.springbeanautowiringsupport;
 
import com.fasterxml.jackson.databind.objectmapper;
import com.xiaofangtech.sunt.jwt.audience;
import com.xiaofangtech.sunt.jwt.jwthelper;
import com.xiaofangtech.sunt.utils.resultmsg;
import com.xiaofangtech.sunt.utils.resultstatuscode;
 
public class httpbearerauthorizeattribute implements filter{
  @autowired
  private audience audienceentity;
 
  @override
  public void init(filterconfig filterconfig) throws servletexception {
    // todo auto-generated method stub
    springbeanautowiringsupport.processinjectionbasedonservletcontext(this,
        filterconfig.getservletcontext());
     
  }
 
  @override
  public void dofilter(servletrequest request, servletresponse response, filterchain chain)
      throws ioexception, servletexception {
    // todo auto-generated method stub
     
    resultmsg resultmsg;
    httpservletrequest httprequest = (httpservletrequest)request;
    string auth = httprequest.getheader("authorization");
    if ((auth != null) && (auth.length() > 7))
    {
      string headstr = auth.substring(0, 6).tolowercase();
      if (headstr.compareto("bearer") == 0)
      {
         
        auth = auth.substring(7, auth.length()); 
        if (jwthelper.parsejwt(auth, audienceentity.getbase64secret()) != null)
        {
          chain.dofilter(request, response);
          return;
        }
      }
    }
     
    httpservletresponse httpresponse = (httpservletresponse) response;
    httpresponse.setcharacterencoding("utf-8"); 
    httpresponse.setcontenttype("application/json; charset=utf-8"); 
    httpresponse.setstatus(httpservletresponse.sc_unauthorized);
 
    objectmapper mapper = new objectmapper();
     
    resultmsg = new resultmsg(resultstatuscode.invalid_token.geterrcode(), resultstatuscode.invalid_token.geterrmsg(), null);
    httpresponse.getwriter().write(mapper.writevalueasstring(resultmsg));
    return;
  }
 
  @override
  public void destroy() {
    // todo auto-generated method stub
     
  }
}

7、在入口处注册filter

?
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
package com.xiaofangtech.sunt;
 
import java.util.arraylist;
import java.util.list;
 
import org.springframework.boot.springapplication;
import org.springframework.boot.autoconfigure.springbootapplication;
import org.springframework.boot.context.embedded.filterregistrationbean;
import org.springframework.boot.context.properties.enableconfigurationproperties;
import org.springframework.context.annotation.bean;
 
import com.xiaofangtech.sunt.filter.httpbasicauthorizeattribute;
import com.xiaofangtech.sunt.filter.httpbearerauthorizeattribute;
import com.xiaofangtech.sunt.jwt.audience;
 
@springbootapplication
@enableconfigurationproperties(audience.class)
public class springrestapplication {
 
  public static void main(string[] args) {
    springapplication.run(springrestapplication.class, args);
  }
   
  @bean
  public filterregistrationbean basicfilterregistrationbean() {
    filterregistrationbean registrationbean = new filterregistrationbean();
    httpbasicauthorizeattribute httpbasicfilter = new httpbasicauthorizeattribute();
    registrationbean.setfilter(httpbasicfilter);
    list<string> urlpatterns = new arraylist<string>();
    urlpatterns.add("/user/getuser");
    registrationbean.seturlpatterns(urlpatterns);
    return registrationbean;
  }
   
  @bean
  public filterregistrationbean jwtfilterregistrationbean(){
    filterregistrationbean registrationbean = new filterregistrationbean();
    httpbearerauthorizeattribute httpbearerfilter = new httpbearerauthorizeattribute();
    registrationbean.setfilter(httpbearerfilter);
    list<string> urlpatterns = new arraylist<string>();
    urlpatterns.add("/user/getusers");
    registrationbean.seturlpatterns(urlpatterns);
    return registrationbean;
  }
}

8、添加获取md5的方法类myutils

?
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
package com.xiaofangtech.sunt.utils;
 
import java.security.messagedigest;
 
public class myutils {
  public static string getmd5(string instr) {
    messagedigest md5 = null;
    try {
      md5 = messagedigest.getinstance("md5");
    } catch (exception e) {
       
      e.printstacktrace();
      return "";
    }
    char[] chararray = instr.tochararray();
    byte[] bytearray = new byte[chararray.length];
  
    for (int i = 0; i < chararray.length; i++)
      bytearray[i] = (byte) chararray[i];
  
    byte[] md5bytes = md5.digest(bytearray);
  
    stringbuffer hexvalue = new stringbuffer();
  
    for (int i = 0; i < md5bytes.length; i++) {
      int val = ((int) md5bytes[i]) & 0xff;
      if (val < 16)
        hexvalue.append("0");
      hexvalue.append(integer.tohexstring(val));
    }
  
    return hexvalue.tostring();
  }
}

9、在返回信息类中补充添加错误码

?
1
2
3
4
invalid_clientid(30003, "invalid clientid"),
invalid_password(30004, "user name or password is incorrect"),
invalid_captcha(30005, "invalid captcha or captcha overdue"),
invalid_token(30006, "invalid token");

10、代码中涉及的audience类,在上一篇文章中定义,本文不再重复说明

11、代码整体结构

 详解Spring Boot实战之Filter实现使用JWT进行接口认证

12、测试

1) 获取token,传入用户认证信息

详解Spring Boot实战之Filter实现使用JWT进行接口认证

认证通过返回token信息

详解Spring Boot实战之Filter实现使用JWT进行接口认证

2) 使用上面获取的token进行接口调用

未使用token,获取token错误,或者token过期时

详解Spring Boot实战之Filter实现使用JWT进行接口认证

使用正确的token时

详解Spring Boot实战之Filter实现使用JWT进行接口认证

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。

原文链接:http://blog.csdn.net/sun_t89/article/details/51923017