欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

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

程序员文章站 2023-11-05 15:16:52
本文介绍了spring boot实战之filter实现使用jwt进行接口认证,分享给大家 jwt(json web token) 用户发送按照约定,向服务端发送 hea...

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

jwt(json web token)

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

jwt使用流程

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

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

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

<dependency> 
  <groupid>io.jsonwebtoken</groupid> 
  <artifactid>jjwt</artifactid> 
  <version>0.6.0</version> 
</dependency> 

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

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

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

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的接口,通过传入用户认证信息(用户名、密码)进行认证获取

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

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

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

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、在返回信息类中补充添加错误码

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进行接口认证

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