本文介紹了spring boot實(shí)戰(zhàn)之filter實(shí)現(xiàn)使用jwt進(jìn)行接口認(rèn)證,分享給大家
jwt(json web token)
用戶發(fā)送按照約定,向服務(wù)端發(fā)送 header、payload 和 signature,并包含認(rèn)證信息(密碼),驗(yàn)證通過后服務(wù)端返回一個(gè)token,之后用戶使用該token作為登錄憑證,適合于移動(dòng)端和api
jwt使用流程
本文示例接上面幾篇文章中的代碼進(jìn)行編寫,請(qǐng)閱讀本文的同時(shí)可以參考前面幾篇文章
1、添加依賴庫(kù)jjwt,本文中構(gòu)造jwt及解析jwt都使用了jjwt庫(kù)
1
2
3
4
5
|
<dependency> <groupid>io.jsonwebtoken</groupid> <artifactid>jjwt</artifactid> <version> 0.6 . 0 </version> </dependency> |
2、添加登錄獲取token時(shí),所需要的認(rèn)證信息類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、添加構(gòu)造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()); //添加構(gòu)成jwt的參數(shù) 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過期時(shí)間 if (ttlmillis >= 0 ) { long expmillis = nowmillis + ttlmillis; date exp = new date(expmillis); builder.setexpiration(exp).setnotbefore(now); } //生成jwt return builder.compact(); } } |
4、添加token返回結(jié)果類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的接口,通過傳入用戶認(rèn)證信息(用戶名、密碼)進(jìn)行認(rèn)證獲取
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; } //驗(yàn)證碼校驗(yàn)在后面章節(jié)添加 //驗(yàn)證用戶名密碼 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認(rèn)證的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、在入口處注冊(cè)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、在返回信息類中補(bǔ)充添加錯(cuò)誤碼
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類,在上一篇文章中定義,本文不再重復(fù)說明
11、代碼整體結(jié)構(gòu)
12、測(cè)試
1) 獲取token,傳入用戶認(rèn)證信息
認(rèn)證通過返回token信息
2) 使用上面獲取的token進(jìn)行接口調(diào)用
未使用token,獲取token錯(cuò)誤,或者token過期時(shí)
使用正確的token時(shí)
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持服務(wù)器之家。
原文鏈接:http://blog.csdn.net/sun_t89/article/details/51923017