详解Spring Boot实战之Filter实现使用JWT进行接口认证
程序员文章站
2023-12-03 18:58:10
本文介绍了spring boot实战之filter实现使用jwt进行接口认证,分享给大家
jwt(json web token)
用户发送按照约定,向服务端发送 hea...
本文介绍了spring boot实战之filter实现使用jwt进行接口认证,分享给大家
jwt(json web token)
用户发送按照约定,向服务端发送 header、payload 和 signature,并包含认证信息(密码),验证通过后服务端返回一个token,之后用户使用该token作为登录凭证,适合于移动端和api
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、代码整体结构
12、测试
1) 获取token,传入用户认证信息
认证通过返回token信息
2) 使用上面获取的token进行接口调用
未使用token,获取token错误,或者token过期时
使用正确的token时
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。