From 95740e2349228e89ef243e5bab87650a03e1f529 Mon Sep 17 00:00:00 2001 From: hgx Date: Thu, 21 Sep 2023 17:57:27 +0800 Subject: [PATCH] =?UTF-8?q?=E7=AC=AC=E4=BA=8C=E8=AF=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Service/VerificationCodeService.java | 8 +- .../controller/TestController.java | 20 ++ .../interceptor/InterceptorConfig.java | 16 ++ .../interceptor/JwtInterceptor.java | 47 +++ .../java/test/{test02.java => Test02.java} | 2 +- api-passenger/src/test/java/test/Test03.java | 174 ++++++++++++ api-passenger/src/test/java/test/Test04.java | 268 ++++++++++++++++++ .../Service/VerificationCodeService.class | Bin 4825 -> 5011 bytes .../controller/TestController.class | Bin 646 -> 1095 bytes .../target/test-classes/test/test02.class | Bin 3943 -> 3943 bytes .../common/constant/IdentityConstant.java | 8 + .../internal/common/dto/TokenResult.java | 11 + .../internal/common/util/JwtUtils.java | 31 +- .../internal/common/util/JwtUtils.class | Bin 3279 -> 4396 bytes 14 files changed, 576 insertions(+), 9 deletions(-) create mode 100644 api-passenger/src/main/java/com/mashibing/apipassenger/interceptor/InterceptorConfig.java create mode 100644 api-passenger/src/main/java/com/mashibing/apipassenger/interceptor/JwtInterceptor.java rename api-passenger/src/test/java/test/{test02.java => Test02.java} (99%) create mode 100644 api-passenger/src/test/java/test/Test03.java create mode 100644 api-passenger/src/test/java/test/Test04.java create mode 100644 internal-common/src/main/java/com/mashibing/internal/common/constant/IdentityConstant.java create mode 100644 internal-common/src/main/java/com/mashibing/internal/common/dto/TokenResult.java diff --git a/api-passenger/src/main/java/com/mashibing/apipassenger/Service/VerificationCodeService.java b/api-passenger/src/main/java/com/mashibing/apipassenger/Service/VerificationCodeService.java index ae6e618..1f501e0 100644 --- a/api-passenger/src/main/java/com/mashibing/apipassenger/Service/VerificationCodeService.java +++ b/api-passenger/src/main/java/com/mashibing/apipassenger/Service/VerificationCodeService.java @@ -3,10 +3,12 @@ package com.mashibing.apipassenger.Service; import com.mashibing.apipassenger.remote.ServicePassengerUserClient; import com.mashibing.apipassenger.remote.ServiceVerificationCodeClient; import com.mashibing.internal.common.constant.CommonStatusEnum; +import com.mashibing.internal.common.constant.IdentityConstant; import com.mashibing.internal.common.dto.ResponseResult; import com.mashibing.internal.common.request.VerificationCodeDTO; import com.mashibing.internal.common.response.NumberCodeResponse; import com.mashibing.internal.common.response.TokenResponse; +import com.mashibing.internal.common.util.JwtUtils; import net.sf.json.JSONObject; import org.apache.commons.lang.StringUtils; import org.springframework.beans.factory.annotation.Autowired; @@ -102,12 +104,12 @@ public class VerificationCodeService { verificationCodeDTO.setPassengerPhone(passengerPhone); servicePassengerUserClient.loginOrRegister(verificationCodeDTO); - // 颁发令牌 - System.out.println("颁发令牌"); + // 颁发令牌,不应用魔法值,用常量 + String token = JwtUtils.generatorToken(passengerPhone, IdentityConstant.PASSENGER_IDENTITY); //响应 TokenResponse tokenResponse = new TokenResponse(); - tokenResponse.setToken("token value"); + tokenResponse.setToken(token); return ResponseResult.success(tokenResponse); } } diff --git a/api-passenger/src/main/java/com/mashibing/apipassenger/controller/TestController.java b/api-passenger/src/main/java/com/mashibing/apipassenger/controller/TestController.java index 4949760..ee8fee5 100644 --- a/api-passenger/src/main/java/com/mashibing/apipassenger/controller/TestController.java +++ b/api-passenger/src/main/java/com/mashibing/apipassenger/controller/TestController.java @@ -1,5 +1,6 @@ package com.mashibing.apipassenger.controller; +import com.mashibing.internal.common.dto.ResponseResult; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @@ -9,4 +10,23 @@ public class TestController { public String test(){ return "test api passenger"; } + + /** + * 需要有token + * @return + */ + @GetMapping("/authTest") + public ResponseResult authTest(){ + return ResponseResult.success("auth test"); + } + + /** + * 不需要有token,没有token也能正常访问 + * @return + */ + @GetMapping("/noAuthTest") + public ResponseResult noAuthTest(){ + return ResponseResult.success("no auth test"); + } + } diff --git a/api-passenger/src/main/java/com/mashibing/apipassenger/interceptor/InterceptorConfig.java b/api-passenger/src/main/java/com/mashibing/apipassenger/interceptor/InterceptorConfig.java new file mode 100644 index 0000000..4da951e --- /dev/null +++ b/api-passenger/src/main/java/com/mashibing/apipassenger/interceptor/InterceptorConfig.java @@ -0,0 +1,16 @@ +package com.mashibing.apipassenger.interceptor; + +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +@Configuration +public class InterceptorConfig implements WebMvcConfigurer { + @Override + public void addInterceptors(InterceptorRegistry registry) { + registry.addInterceptor(new JwtInterceptor()) + // 拦截的路径 + .addPathPatterns("/**") + // 不拦截的路径 + .excludePathPatterns("/noAuthTest"); + } +} diff --git a/api-passenger/src/main/java/com/mashibing/apipassenger/interceptor/JwtInterceptor.java b/api-passenger/src/main/java/com/mashibing/apipassenger/interceptor/JwtInterceptor.java new file mode 100644 index 0000000..8ff963e --- /dev/null +++ b/api-passenger/src/main/java/com/mashibing/apipassenger/interceptor/JwtInterceptor.java @@ -0,0 +1,47 @@ +package com.mashibing.apipassenger.interceptor; + +import com.auth0.jwt.exceptions.AlgorithmMismatchException; +import com.auth0.jwt.exceptions.SignatureVerificationException; +import com.auth0.jwt.exceptions.TokenExpiredException; +import com.mashibing.internal.common.dto.ResponseResult; +import com.mashibing.internal.common.util.JwtUtils; +import net.sf.json.JSONObject; +import org.springframework.web.servlet.HandlerInterceptor; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.PrintWriter; + +public class JwtInterceptor implements HandlerInterceptor { + + @Override + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { + + boolean result = true; + String resultString = ""; + String token = request.getHeader("Authorization"); + + try { + + JwtUtils.parseToken(token); + }catch(SignatureVerificationException e){ + resultString = "token sign error"; + result = false; + }catch(TokenExpiredException e){ + resultString = "token time out"; + result = false; + }catch(AlgorithmMismatchException e){ + resultString = "token AlgorithmMismatchException"; + result = false; + }catch(Exception e){ + resultString = "token invalid"; + result = false; + } + + if(!result){ + PrintWriter out = response.getWriter(); + out.println(JSONObject.fromObject(ResponseResult.fail(resultString)).toString()); + } + return result; + } +} diff --git a/api-passenger/src/test/java/test/test02.java b/api-passenger/src/test/java/test/Test02.java similarity index 99% rename from api-passenger/src/test/java/test/test02.java rename to api-passenger/src/test/java/test/Test02.java index 4323ac4..ba2e553 100644 --- a/api-passenger/src/test/java/test/test02.java +++ b/api-passenger/src/test/java/test/Test02.java @@ -6,7 +6,7 @@ import java.util.Arrays; import java.util.HashMap; import java.util.Map; -public class test02 { +public class Test02 { @Test public void test01() { int[] arr = {421, 240, 115, 532, 305, 430, 124}; diff --git a/api-passenger/src/test/java/test/Test03.java b/api-passenger/src/test/java/test/Test03.java new file mode 100644 index 0000000..bc24f4d --- /dev/null +++ b/api-passenger/src/test/java/test/Test03.java @@ -0,0 +1,174 @@ +package test; + +import org.junit.Test; + +public class Test03 { + @Test + public void test01(){ + /** + *求n的阶乘 + * 找重复 + * 找变化 + * 找边界 + */ + System.out.println(f1(10)); + } + public int f1(int n){ + if(n == 1){ + return 1; + } + return n * f1(n-1); + } + + @Test + public void test02(){ + /** + * 打印1-10; + */ + f2(1,10); + } + void f2(int i,int j){ + if(i>j){ + return; + } + System.out.println(i); + f2(i+1,j); + } + + int f3(int[] arr,int begin){ + if(begin == arr.length -1){ + return arr[begin]; + } + return arr[begin]+f3(arr,begin+1); + } + + @Test + public void test03(){ + int res = f3(new int[]{1,2,3,4,5},0); + System.out.println(res); + } + + /** + * 翻转字符串 + */ + String reverse(String src,int end){ + if(end ==0){ + return ""+src.charAt(0); + } + return src.charAt(end) + reverse(src,end-1); + } + @Test + public void test04(){ + String str = reverse("abcd",3); + System.out.println(str); + } + + int f5(int n){ + if(n==1 || n==2){ + return 1; + } + return f5(n-1)+f5(n-2); + } + + @Test + public void test05(){ + int result = f5(10); + System.out.println(result); + } + + /** + * 对数组排序 + * 等价于: + * 对数组的0-倒数第二个元素这部分排序 + * 然后把最后一个元素插入这个有序的部分中 + */ + void insertSort(int[] arr,int k){ + if(k==0){ + return; + } + //对前k-1个元素排序 + insertSort(arr,k-1); + //把位置k的元素插入到前面的部分 + int x= arr[k]; + int index = k-1; + while(x high){ + return -1; + } + int mid = low + (high -low)>>1; // (low+high)>>1,防止溢出,移位也更高效 + int midVal = arr[mid]; + if(midVal key){ + return binarySearch(arr,low,high-1,key); + }else { + return mid; + } + } + + @Test + public void test07(){ + int search = binarySearch(new int[]{3, 5, 4, 7, 8, 1}, 0, 5, 4); + System.out.println(search); + } + + void shellSort(int[] arr){ + //不断地缩小增量 + for(int interval = arr.length/2;interval>0;interval=interval/2){ + //增量为1的插入排序 + for(int i=interval;i-1 && target < arr[j]){ + arr[j+interval] =arr[j]; + j-=interval; + } + arr[j+interval] =target; + } + } + } +} diff --git a/api-passenger/src/test/java/test/Test04.java b/api-passenger/src/test/java/test/Test04.java new file mode 100644 index 0000000..ef24680 --- /dev/null +++ b/api-passenger/src/test/java/test/Test04.java @@ -0,0 +1,268 @@ +package test; + +import org.junit.Test; + +import java.util.Hashtable; +import java.util.Map; +import java.util.TreeMap; + +public class Test04 { + + /** + * 1.两数之和 + * 给定一个整数数组nums和一个整数目标值target,请你在该数组中找出和为目标值的那两个整数,并返回它们的数组下标。 + * 你可以假设每种输入只会对应一个答案。但是,数组中同一个元素不能使用两遍。 + */ + @Test + public void test01(){ + int[] result = new int[2]; + int[] str = new int[]{2,7,8,69}; + int target =9; + for(int i=0;i map = new Hashtable<>(); + for(int i=0;i n0,有 0< f(n) <= cg(n)} + * O(n) = 2n^2 + n + 5 + * O(g(n)),表示这个算法是有一个渐进上届的,这个渐进上界为g(n),算法的运行时间f(n)趋近并小于等于这个g(n) + */ + + /** + * 2.两数相加 + * 给你两个非空的链表,表示两个非负的整数。它们每位数字都是按照逆序的方式存储的,并且每个节点只能存储一位数字。 + * 请你将两个数相加,并以相同形式返回一个表示和的链表。 + * 你可以假设除了数字0之外,这两个数都不会以0开头。 + * + */ + + void print(int num){ + for(int i =31;i>= 0;i--){ + System.out.print((num & (1<= 0;end--){ + // 0~ end 干一陀事情 + // 0 1 1 2 2 3 3 4 4 5 end-1 end + for(int second =1;second <= end;second++){ + if(arr[second -1]> arr[second]){ + swap(arr,second -1,second); + } + } + } + } + + @Test + public void test09(){ + int[] arr= {7,1,3,5,1,6,8,1,3,5,7,5,6}; + printArray(arr); + insertSort(arr); + printArray(arr); + } + + void insertSort(int[] arr) { + if(arr == null || arr.length <2){ + return; + } + // 0~0完成 + //0~1 + //0~2 + //0~3 + //0~n-1 + int n = arr.length; + for(int end = 1;end =0 && arr[newNumIndex-1]>arr[newNumIndex]){ + swap(arr,newNumIndex -1,newNumIndex); + newNumIndex--; + } + } + } + + + @Test + public void test10(){ + int[] arr= {7,1,3,5,1,6,8,1,3,5,7,5,6}; + printArray(arr); + insertSort1(arr); + printArray(arr); + } + + void insertSort1(int[] arr) { + if(arr == null || arr.length <2){ + return; + } + // 0~0完成 + //0~1 + //0~2 + //0~3 + //0~n-1 + int n = arr.length; + for(int end = 1;end =0 && arr[pre]>arr[pre+1];pre--){ + swap(arr,pre,pre+1); + } + } + } + @Test + public void test11(){ + new RangeSum(new int[]{4,5,6,7,7,8}); + System.out.println(RangeSum.rangeSum(1, 3)); + } + +} +class RangeSum{ + private static int[] preSum; + + public RangeSum(int[] array){ + int n = array.length; + preSum = new int[n]; + preSum[0] = array[0]; + for(int i=1;iBWJMU6YS1|dO6B!c2@+!Y@zUwre?XCGWnPbkXLTetr1K7E$|{I~o5e5NfgjQ(}- zFffasG#AhskV!C`TN12hO+Z$2D{GylEy-=$YiR+DxfY5H9BbBgB`FL<2RnaOu$ zTQW-r{^*PO@vwbuCTDGYxwqN=9&d_X!lky(pPHP{g^CvqFY&VN_RpF8ieV?a40D*P zc-8P4uPfd#yvbX3LU4wyi>2bu+He2%)8lsYwqZAW40{={3sh>_5*iE(s8$Rb_VJDf ziv5NI3@L^U?{d&E!h3d;njSsGVY^4oFMr?g0Y?-c8b0DD}SE^5u>!fe=6)1K=Ln{%OumsWgd_?{nZE|{YYKf1UP zj_x}YoZ@?x_J}`a>iRI-He+#j*dSx4N6G3;E|YH#+w)7DS{`$4bK(U1OKg(es7vk9 zlE%VpIYAI3;snBDo~(QstK26?#4L`||Nr)c@_%eGS<7b-tdXdB5-(zrtQf+pm>Ahl zbfB25R#3|(oJd)W$t;wq8S~{bE|-O15hntPn{#OEzrBYs+lRi6y zLSXAB>?l-DoH5MIDu0A@(-7xXsgz3j2RJ{ahMBcjaz>?3MBP%sdeNbQ5*j(3Ch6cN zv9FLyD_JHzW@({Eeg?g)VXLgR(?*|MrCoH;&$=Q{mjMQk^V~3ajHoj7j^e33{=s1_nxLkDG*{ zshMs|Dti%>R+K=3iP`&QkKdcA-(s46>K~}4wGP%ab>`06d#}B|Ykk-EtaDxY4;SW7 z|9RpRP|f!tm(molIwglSDY7&NtPQ!BoO;%!S#187(qrm43&l_IwIIlh1){$GC zU7BsnHRs#{uV8qJ*By7gi3YFB{hnxuUBk6*S#nxB!#u+w%Zt3^x{|X>Ubei#tCq{S z+|X-zjXp!a<#pb0Q-cd!UA#C@?_rN3Hy9SV>85DW5#F>M;VsMC40t4~Dy!u2NRJQn zjBoF6%dW|_Tkhaa%avSZc*pWCM?EkMT80=lyk|Mah-H-HZkL%Id!G~Tq?uPfW;w|R zhEtXg`N;Ayhb^BlVEL5KET8M{3%(R?HRpe&#A~?P@U`VM-+0(xd$*16-S_iY-!D6N zdsMq=L7B8*+>gPe65+S0b$zy_tfO(m=B(vgg^%)`N5(DoOWbdM>2PK0r-bXCyd+;O zg9CAVRR)hM$!zni3vW#BDsx=eqQ1%()UGz#H7f6mPI0U uQb~gpNl3CuQg($jzfuxe{6AQ3xLbZxBeha~q*lFL`rH%QRsT#^Bm4yrE78LM diff --git a/api-passenger/target/classes/com/mashibing/apipassenger/controller/TestController.class b/api-passenger/target/classes/com/mashibing/apipassenger/controller/TestController.class index 1428cdd8162cf0174d5c99d1ff24c6e2a99908a7..d829c78abe93f3ef45459037a0b63f5432f71a34 100644 GIT binary patch literal 1095 zcmbVLO>Yx15PfdGwn-=@4Ic$cx3oZt1n!|iNJU6hrE&=%wN);hoQ+9bcJ0;L+x{&$ zfjIC3_)&;)6QvteM8rzF_KauV%zNYg`Rn@+0K4eaQNvn*2LaaW2(c01VGWx#Y%x?{ zDXrXVhEiv{$51{n1Ici`tF(NVCw-Znh<;3-R@X!#?ukr!d*Up+k+KXgx{*nEBJ4=@ zl^$}Ds#I7j^-yL!GTLP(j%j-$tvi^SdsNMlhoRls?w*P>!DB($$1WofI$b@=wNr`g zDXXaFzShPGr;MhOyIqqFxlMiO$4n&h++?5lx$JZ5V8F#RmcNnitw_@`WaUi6IkBnm zapgedZsgk{L~3G|hSE-ETEs*lNsQ(LXZVq{DK#Kz&0|MRF7iu=x;Fb$yaq2?^<$G~ zkvvph%avIno_p>LFXyI2#fv&N5nz!f*)J?=^ zS);B=rWx zEKx#>-jxqv7H!(y#H|V34p|ObVw*owh3YZN(P{#qCuX34WL4zphaRARzRGS0xbDX zr@LoAql3v`pZfzqiJ3zSlL%9b%pyN8#2;m&4ch)KnUtq(>DMaVV-C$_I0^#xRLfM* zg>IHN$hEE`YN)|MhuUifaOg4#bDxg{c*PWUI#Cyz!Vh(Ss7BGSF-I|p0q?Ma>@Xsf M)M(14`F9L_0iQw~f3`C+hHT!##08@EGq2zV0HKl!mH+?% delta 26 gcmaDZ_grqmZ^n|1f3`C+mTca_#08@EGq2zV0H#t3_5c6? diff --git a/internal-common/src/main/java/com/mashibing/internal/common/constant/IdentityConstant.java b/internal-common/src/main/java/com/mashibing/internal/common/constant/IdentityConstant.java new file mode 100644 index 0000000..e2ef1a8 --- /dev/null +++ b/internal-common/src/main/java/com/mashibing/internal/common/constant/IdentityConstant.java @@ -0,0 +1,8 @@ +package com.mashibing.internal.common.constant; + +public class IdentityConstant { + //乘客身份 + public static final String PASSENGER_IDENTITY = "1"; + //司机身份 + public static final String DRIVER_IDENTITY = "2"; +} diff --git a/internal-common/src/main/java/com/mashibing/internal/common/dto/TokenResult.java b/internal-common/src/main/java/com/mashibing/internal/common/dto/TokenResult.java new file mode 100644 index 0000000..0114540 --- /dev/null +++ b/internal-common/src/main/java/com/mashibing/internal/common/dto/TokenResult.java @@ -0,0 +1,11 @@ +package com.mashibing.internal.common.dto; + +import lombok.Data; + +@Data +public class TokenResult { + + private String phone; + + private String identity; +} diff --git a/internal-common/src/main/java/com/mashibing/internal/common/util/JwtUtils.java b/internal-common/src/main/java/com/mashibing/internal/common/util/JwtUtils.java index 44f5d63..710563e 100644 --- a/internal-common/src/main/java/com/mashibing/internal/common/util/JwtUtils.java +++ b/internal-common/src/main/java/com/mashibing/internal/common/util/JwtUtils.java @@ -3,6 +3,9 @@ package com.mashibing.internal.common.util; import com.auth0.jwt.JWT; import com.auth0.jwt.JWTCreator; import com.auth0.jwt.algorithms.Algorithm; +import com.auth0.jwt.interfaces.Claim; +import com.auth0.jwt.interfaces.DecodedJWT; +import com.mashibing.internal.common.dto.TokenResult; import java.util.Calendar; import java.util.Date; @@ -13,8 +16,15 @@ public class JwtUtils { //盐 private static final String SIGN = "CPFmsb!@#$$"; + private static final String JWT_KEY_PHONE = "Phone"; + //乘客是1,司机是2 + private static final String JWT_KEY_IDENTITY = "identity"; + //生成token - public static String generatorToken(Map map){ + public static String generatorToken(String passengerPhone,String identity){ + Map map =new HashMap<>(); + map.put(JWT_KEY_PHONE,passengerPhone); + map.put(JWT_KEY_IDENTITY,identity); //token过期时间 Calendar calendar = Calendar.getInstance(); calendar.add(Calendar.DATE,1); @@ -32,12 +42,23 @@ public class JwtUtils { } //解析token + public static TokenResult parseToken(String token){ + DecodedJWT verify = JWT.require(Algorithm.HMAC256(SIGN)).build().verify(token); + String phone = verify.getClaim(JWT_KEY_PHONE).toString(); + String identity = verify.getClaim(JWT_KEY_IDENTITY).toString(); + + TokenResult tokenResult = new TokenResult(); + tokenResult.setPhone(phone); + tokenResult.setIdentity(identity); + + return tokenResult; + } public static void main(String[] args) { - Map map = new HashMap<>(); - map.put("name","zhangsan"); - map.put("age","18"); - String s = generatorToken(map); + String s = generatorToken("13571876296","1"); System.out.println("生成的token:"+s); + TokenResult tokenResult = parseToken(s); + System.out.println("手机号:"+tokenResult.getPhone()); + System.out.println("身份:"+tokenResult.getIdentity()); } } diff --git a/internal-common/target/classes/com/mashibing/internal/common/util/JwtUtils.class b/internal-common/target/classes/com/mashibing/internal/common/util/JwtUtils.class index 2076d7263362d84be82d03eeaaf2dfe63e529af3..a64fd0d1d460e71977dc58006453d5cbeb236f0a 100644 GIT binary patch literal 4396 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