From 4fce30fdc7c66463791ef209c058eb6761016d08 Mon Sep 17 00:00:00 2001 From: Chantha Date: Tue, 19 May 2020 16:51:38 +0700 Subject: [PATCH] JWT Token --- .../Maven__io_jsonwebtoken_jjwt_0_9_1.xml | 13 ++++ .idea/workspace.xml | 69 +++++++++--------- jdbc.iml | 1 + pom.xml | 5 ++ .../com/chantha/jdbc/config/WebConfig.java | 6 +- .../jdbc/security/UserDetailServiceImpl.kt | 5 +- .../jwt/JwtAuthenticationEntryPoint.java | 19 +++++ .../chantha/jdbc/utils/jwt/JwtRequest.java | 28 +++++++ .../jdbc/utils/jwt/JwtRequestFilter.java | 63 ++++++++++++++++ .../chantha/jdbc/utils/jwt/JwtResponse.java | 16 ++++ .../chantha/jdbc/utils/jwt/JwtTokenUtil.java | 63 ++++++++++++++++ src/main/resources/application.properties | 2 + target/classes/application.properties | 2 + .../com/chantha/jdbc/config/WebConfig.class | Bin 4415 -> 4763 bytes .../jdbc/security/UserDetailServiceImpl.class | Bin 2124 -> 2176 bytes .../jwt/JwtAuthenticationEntryPoint.class | Bin 0 -> 1238 bytes .../chantha/jdbc/utils/jwt/JwtRequest.class | Bin 0 -> 1082 bytes .../jdbc/utils/jwt/JwtRequestFilter.class | Bin 0 -> 4172 bytes .../chantha/jdbc/utils/jwt/JwtResponse.class | Bin 0 -> 626 bytes .../chantha/jdbc/utils/jwt/JwtTokenUtil.class | Bin 0 -> 5157 bytes 20 files changed, 253 insertions(+), 39 deletions(-) create mode 100644 .idea/libraries/Maven__io_jsonwebtoken_jjwt_0_9_1.xml create mode 100644 src/main/kotlin/com/chantha/jdbc/utils/jwt/JwtAuthenticationEntryPoint.java create mode 100644 src/main/kotlin/com/chantha/jdbc/utils/jwt/JwtRequest.java create mode 100644 src/main/kotlin/com/chantha/jdbc/utils/jwt/JwtRequestFilter.java create mode 100644 src/main/kotlin/com/chantha/jdbc/utils/jwt/JwtResponse.java create mode 100644 src/main/kotlin/com/chantha/jdbc/utils/jwt/JwtTokenUtil.java create mode 100644 target/classes/com/chantha/jdbc/utils/jwt/JwtAuthenticationEntryPoint.class create mode 100644 target/classes/com/chantha/jdbc/utils/jwt/JwtRequest.class create mode 100644 target/classes/com/chantha/jdbc/utils/jwt/JwtRequestFilter.class create mode 100644 target/classes/com/chantha/jdbc/utils/jwt/JwtResponse.class create mode 100644 target/classes/com/chantha/jdbc/utils/jwt/JwtTokenUtil.class diff --git a/.idea/libraries/Maven__io_jsonwebtoken_jjwt_0_9_1.xml b/.idea/libraries/Maven__io_jsonwebtoken_jjwt_0_9_1.xml new file mode 100644 index 0000000..f25b99b --- /dev/null +++ b/.idea/libraries/Maven__io_jsonwebtoken_jjwt_0_9_1.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/workspace.xml b/.idea/workspace.xml index aaad21d..13ec0f6 100644 --- a/.idea/workspace.xml +++ b/.idea/workspace.xml @@ -2,27 +2,20 @@ - - - - - - - - + + + + + + - - - - - @@ -71,7 +64,7 @@ - + @@ -112,7 +105,7 @@ - + 1589796661163 @@ -140,6 +133,10 @@ + + + + @@ -160,42 +157,42 @@ - + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - + @@ -224,9 +221,9 @@ - + - + \ No newline at end of file diff --git a/jdbc.iml b/jdbc.iml index d39a43e..222e5ac 100644 --- a/jdbc.iml +++ b/jdbc.iml @@ -176,5 +176,6 @@ + \ No newline at end of file diff --git a/pom.xml b/pom.xml index b8fbc16..efad85f 100644 --- a/pom.xml +++ b/pom.xml @@ -77,6 +77,11 @@ + + io.jsonwebtoken + jjwt + 0.9.1 + diff --git a/src/main/kotlin/com/chantha/jdbc/config/WebConfig.java b/src/main/kotlin/com/chantha/jdbc/config/WebConfig.java index e637a2f..c5811e4 100644 --- a/src/main/kotlin/com/chantha/jdbc/config/WebConfig.java +++ b/src/main/kotlin/com/chantha/jdbc/config/WebConfig.java @@ -1,5 +1,6 @@ package com.chantha.jdbc.config; +import com.chantha.jdbc.utils.jwt.JwtRequestFilter; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -13,6 +14,7 @@ import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import org.springframework.security.web.util.matcher.AntPathRequestMatcher; @Configuration @@ -21,7 +23,8 @@ public class WebConfig extends WebSecurityConfigurerAdapter { private final UserDetailsService userDetailsService; - + @Autowired + private JwtRequestFilter jwtRequestFilter; @Autowired public WebConfig(UserDetailsService userDetailsService){ @@ -41,6 +44,7 @@ public class WebConfig extends WebSecurityConfigurerAdapter { .antMatchers("/register").permitAll() .antMatchers("/**").hasAnyRole("ADMIN"); http.csrf().disable(); + http.addFilterBefore(jwtRequestFilter,UsernamePasswordAuthenticationFilter.class); } @Bean diff --git a/src/main/kotlin/com/chantha/jdbc/security/UserDetailServiceImpl.kt b/src/main/kotlin/com/chantha/jdbc/security/UserDetailServiceImpl.kt index 661b853..d80d5c1 100644 --- a/src/main/kotlin/com/chantha/jdbc/security/UserDetailServiceImpl.kt +++ b/src/main/kotlin/com/chantha/jdbc/security/UserDetailServiceImpl.kt @@ -3,13 +3,14 @@ package com.chantha.jdbc.security import org.springframework.beans.factory.annotation.Autowired import org.springframework.security.core.userdetails.UserDetails import org.springframework.security.core.userdetails.UserDetailsService +import org.springframework.security.core.userdetails.UsernameNotFoundException import org.springframework.stereotype.Service @Service class UserDetailServiceImpl @Autowired constructor(private val userRepo: UserRepo):UserDetailsService { - @Throws(Exception::class) + @Throws(UsernameNotFoundException::class) override fun loadUserByUsername(p0: String?): UserDetails { - val user=userRepo.findByUsername(p0!!) + val user = userRepo.findByUsername(p0!!) return UserPrincipal(user) } diff --git a/src/main/kotlin/com/chantha/jdbc/utils/jwt/JwtAuthenticationEntryPoint.java b/src/main/kotlin/com/chantha/jdbc/utils/jwt/JwtAuthenticationEntryPoint.java new file mode 100644 index 0000000..3459a98 --- /dev/null +++ b/src/main/kotlin/com/chantha/jdbc/utils/jwt/JwtAuthenticationEntryPoint.java @@ -0,0 +1,19 @@ +package com.chantha.jdbc.utils.jwt; + + +import java.io.IOException; +import java.io.Serializable; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.web.AuthenticationEntryPoint; +import org.springframework.stereotype.Component; +@Component +public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint, Serializable { + private static final long serialVersionUID = -7858869558953243875L; + @Override + public void commence(HttpServletRequest request, HttpServletResponse response, + AuthenticationException authException) throws IOException { + response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized"); + } +} diff --git a/src/main/kotlin/com/chantha/jdbc/utils/jwt/JwtRequest.java b/src/main/kotlin/com/chantha/jdbc/utils/jwt/JwtRequest.java new file mode 100644 index 0000000..7814f2d --- /dev/null +++ b/src/main/kotlin/com/chantha/jdbc/utils/jwt/JwtRequest.java @@ -0,0 +1,28 @@ +package com.chantha.jdbc.utils.jwt; + +import java.io.Serializable; +public class JwtRequest implements Serializable { + private static final long serialVersionUID = 5926468583005150707L; + private String username; + private String password; + //need default constructor for JSON Parsing + public JwtRequest() + { + } + public JwtRequest(String username, String password) { + this.setUsername(username); + this.setPassword(password); + } + public String getUsername() { + return this.username; + } + public void setUsername(String username) { + this.username = username; + } + public String getPassword() { + return this.password; + } + public void setPassword(String password) { + this.password = password; + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/chantha/jdbc/utils/jwt/JwtRequestFilter.java b/src/main/kotlin/com/chantha/jdbc/utils/jwt/JwtRequestFilter.java new file mode 100644 index 0000000..8cc54e7 --- /dev/null +++ b/src/main/kotlin/com/chantha/jdbc/utils/jwt/JwtRequestFilter.java @@ -0,0 +1,63 @@ +package com.chantha.jdbc.utils.jwt; + +import java.io.IOException; +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.web.authentication.WebAuthenticationDetailsSource; +import org.springframework.stereotype.Component; +import org.springframework.web.filter.OncePerRequestFilter; +import com.chantha.jdbc.security.UserDetailServiceImpl; +import io.jsonwebtoken.ExpiredJwtException; +@Component +public class JwtRequestFilter extends OncePerRequestFilter { + + @Autowired + private UserDetailServiceImpl jwtUserDetailsService; + + @Autowired + private JwtTokenUtil jwtTokenUtil; + @Override + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) + throws ServletException, IOException { + final String requestTokenHeader = request.getHeader("Authorization"); + String username = null; + String jwtToken = null; + // JWT Token is in the form "Bearer token". Remove Bearer word and get + // only the Token + if (requestTokenHeader != null && requestTokenHeader.startsWith("Bearer ")) { + jwtToken = requestTokenHeader.substring(7); + try { + username = jwtTokenUtil.getUsernameFromToken(jwtToken); + } catch (IllegalArgumentException e) { + System.out.println("Unable to get JWT Token"); + } catch (ExpiredJwtException e) { + System.out.println("JWT Token has expired"); + } + } else { + logger.warn("JWT Token does not begin with Bearer String"); + } + // Once we get the token validate it. + if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) { + UserDetails userDetails = this.jwtUserDetailsService.loadUserByUsername(username); + // if token is valid configure Spring Security to manually set + // authentication + if (jwtTokenUtil.validateToken(jwtToken, userDetails)) { + UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken( + userDetails, null, userDetails.getAuthorities()); + usernamePasswordAuthenticationToken + .setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); + // After setting the Authentication in the context, we specify + // that the current user is authenticated. So it passes the + // Spring Security Configurations successfully. + SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken); + } + } + chain.doFilter(request, response); + } +} diff --git a/src/main/kotlin/com/chantha/jdbc/utils/jwt/JwtResponse.java b/src/main/kotlin/com/chantha/jdbc/utils/jwt/JwtResponse.java new file mode 100644 index 0000000..a910d54 --- /dev/null +++ b/src/main/kotlin/com/chantha/jdbc/utils/jwt/JwtResponse.java @@ -0,0 +1,16 @@ +package com.chantha.jdbc.utils.jwt; + +import java.io.Serializable; + +public class JwtResponse implements Serializable { + private static final long serialVersionUID = -8091879091924046844L; + private final String jwttoken; + + public JwtResponse(String jwttoken) { + this.jwttoken = jwttoken; + } + public String getToken() { + return this.jwttoken; + } + +} diff --git a/src/main/kotlin/com/chantha/jdbc/utils/jwt/JwtTokenUtil.java b/src/main/kotlin/com/chantha/jdbc/utils/jwt/JwtTokenUtil.java new file mode 100644 index 0000000..edce46c --- /dev/null +++ b/src/main/kotlin/com/chantha/jdbc/utils/jwt/JwtTokenUtil.java @@ -0,0 +1,63 @@ +package com.chantha.jdbc.utils.jwt; + +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.SignatureAlgorithm; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.stereotype.Component; + +import java.io.Serializable; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; +import java.util.function.Function; + +@Component +public class JwtTokenUtil implements Serializable { + private static final long serialVersionUID = -2550185165626007488L; + public static final long JWT_TOKEN_VALIDITY = 5 * 60 * 60; + @Value("${jwt.secret}") + private String secret; + //retrieve username from jwt token + public String getUsernameFromToken(String token) { + return getClaimFromToken(token, Claims::getSubject); + } + //retrieve expiration date from jwt token + public Date getExpirationDateFromToken(String token) { + return getClaimFromToken(token, Claims::getExpiration); + } + public T getClaimFromToken(String token, Function claimsResolver) { + final Claims claims = getAllClaimsFromToken(token); + return claimsResolver.apply(claims); + } + //for retrieveing any information from token we will need the secret key + private Claims getAllClaimsFromToken(String token) { + return Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody(); + } + //check if the token has expired + private Boolean isTokenExpired(String token) { + final Date expiration = getExpirationDateFromToken(token); + return expiration.before(new Date()); + } + //generate token for user + public String generateToken(UserDetails userDetails) { + Map claims = new HashMap<>(); + return doGenerateToken(claims, userDetails.getUsername()); + } + //while creating the token - + //1. Define claims of the token, like Issuer, Expiration, Subject, and the ID + //2. Sign the JWT using the HS512 algorithm and secret key. + //3. According to JWS Compact Serialization(https://tools.ietf.org/html/draft-ietf-jose-json-web-signature-41#section-3.1) + // compaction of the JWT to a URL-safe string + private String doGenerateToken(Map claims, String subject) { + return Jwts.builder().setClaims(claims).setSubject(subject).setIssuedAt(new Date(System.currentTimeMillis())) + .setExpiration(new Date(System.currentTimeMillis() + JWT_TOKEN_VALIDITY * 1000)) + .signWith(SignatureAlgorithm.HS512, secret).compact(); + } + //validate token + public Boolean validateToken(String token, UserDetails userDetails) { + final String username = getUsernameFromToken(token); + return (username.equals(userDetails.getUsername()) && !isTokenExpired(token)); + } +} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 5a53e97..d976841 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -7,6 +7,8 @@ spring.jpa.open-in-view=true server.port=8081 spring.thymeleaf.cache=true +jwt.secret=javainuse + diff --git a/target/classes/application.properties b/target/classes/application.properties index 5a53e97..d976841 100644 --- a/target/classes/application.properties +++ b/target/classes/application.properties @@ -7,6 +7,8 @@ spring.jpa.open-in-view=true server.port=8081 spring.thymeleaf.cache=true +jwt.secret=javainuse + diff --git a/target/classes/com/chantha/jdbc/config/WebConfig.class b/target/classes/com/chantha/jdbc/config/WebConfig.class index aaba873fea325be8d181f49c24a4d811f0942de4..5d2d5fb5a0356263e924642599ec2c240a3d3316 100644 GIT binary patch delta 994 zcmZuw%Tg0T6g?dhW|$f!P$ejeN(c%QU=;8f1OkYF0TFqK#K({fBrznCnGk$N|A5pi zU0Cj2XrWT2RkCNz#*I~O-MY8DJ%gZ>i|*66`}R4fZ+CC_UN#gqe|`D_paU-?)S|Nt zM{r3(7rG@H^+*VzS3)29d3RaBfQTy+L<~w8!Z4q_Dj+OkM8YVp3Air7iwO~vBBuCo zny1{9FoRp1dR9P$&)gPpM?wucO9k8&aId%$33-!wb6j7_>4rIwNSS(;p(Py6EUMAC zmNw&>nvBgw)ts3~87if!!+X+$R*}sVw>GRF>?hOKzPY|K#g91|M{!I*lw(ZB8JrcM zbDS5jAR~^1j3n+`-`(S0KT-k~Wu%dj@c>z?&r>HGGEC$IEHf-w#eFer%hMXjgY1>4 zio)Ot^^XjV%2>fe8ISN-z!Moy@l3{X)Gy9U^Ir4+OoEy66118 zH&tgjXwRxCExn-jrAQ^%WNGdWYqjh^A&5G=F3|gOA3gg!P1OLO&W% zf)f-CP_~OuQr5wgzz4YAQRKo&>i1I)h{;V{WpwgJimIG!G(n+=_Ss4d0WRlZ6k(5A zGg`Qo^{U)A#aShr!A}pV;V;ID9mWc@LM4x9wKO`@ADrI?L^1; zgCk{LzBWQeD8@gdW@a6S-%{XIkJp=jLe4KcN!$E?ZsQ!Sl;FI*ZeAIh>5a3K!-gaD z8DU2a$2e{{!AWQOH3L4U3_hm~gPd`}vzl{0Lxu|HH5UyDF8Ne_YL1S&lFNoGjA_OV zP4sFeG*=akiwo29%Wubm*J?FrRTDv9!%tOTDMh}iVv1{)7ItZ_JG@~zK&R%W!&{o$ zmOI?F++#B6^hOgYrZm%*`#i8bWF`o_tbJ^G!c)yN#ayr)F9$!o$^3I>6p?bVsPF~` zhbtqNS>`PBENEU>7I~@Ym-2Kl8;`C0immx+vT}-MIg;$`mJ${fo+3?z-NBngOEn|0 zZQ>#Ms8qxyn-y<64Pp&B_6R!W`W3ChJtYpb$%{!SFBqkrj!^V_A~&9qhzSL?93 zg2^qxBn67ny*KPu?Aw$sY{>0*a>C!^g;KR(Dp_6nD3Jy-V$*1`dC9iRwjHu(fgX_@ z63ME_{r!sC*3cRy%KsZ$5-H_=m595cU4lx`|3Xv!6FWW#cVp}8pNy0`eY;+?p}%>M iF3ChV7`AkWXL85r5&w|95qXW`C%C|{^j8EQq5c5GT2Lwg diff --git a/target/classes/com/chantha/jdbc/security/UserDetailServiceImpl.class b/target/classes/com/chantha/jdbc/security/UserDetailServiceImpl.class index f7af3aff9798af4d6e9bb0a3ffb84671c868c803..369e425b1fb1ec6ecaa2084ba12543990e5aa591 100644 GIT binary patch delta 50 zcmX>j&>*-$pOMjh@&{&-i8*pSd5O8He)%PC`K5U&o2?k{va<3r2r=+YmSOK?-pK*%os685Z?P`}0QZ~=*#H0l diff --git a/target/classes/com/chantha/jdbc/utils/jwt/JwtAuthenticationEntryPoint.class b/target/classes/com/chantha/jdbc/utils/jwt/JwtAuthenticationEntryPoint.class new file mode 100644 index 0000000000000000000000000000000000000000..3c50e1e6625ebe96b5358ba533471eff2a3987c0 GIT binary patch literal 1238 zcmbtTT~8B16g|@x7Rn+}5Jg164=5Fx#2BNgF(HT%QiV`yeBEwGI<=jtv$GWV4?gH0 zF+Lf6@X-hVjQ_xRcella7@Ek#eC*vj=iIsH%+KH7z5}=qp2Z+;Ik-K9#Sx^iQ!ZU8}%)%2vE)C$)Zw#!6C&mtm_a%qy?jq)4u$eS-A}oW8rkjIGOn;bFhOEqmMYmRobRJO=4L?>H9`NZ%(Uut*<-XW(O95jXHb!*%F zIZfpxuq)n$BCy52X+fJVD~cs;_Ic1YQtiJnUQ2Yec}w7aXrw*jzBYoNs_f7g?Wn|J z)C$KWd<;u{8I!{3Iz}Yq4E=A@EtACYs6iV&a)$F%&X7Gp3LLDEBVGtw*R>rl>VYL+ zP)b>c#uv|Ir0o0|3av(pFwE?RBwtHZWFSfXHKnwTwIr;*sDKF~&c!%|B)5wb;aUz5{rGW)2zL%pr|iVs2+?cEsGt zpq4>BgN8yWbOP5Jb(|n{eed|$69sjku(I!ap|(8Tu||=TI(nQxJNxkSm%@dJ37&Q0 zD3n`6>z!qeEU$02b>Mpahy4G>3d6A<^c2#MT+h{e3dwq-qhRd&J!TbKuIIdnPP$I; z%Ic0{9p5H_MGo$#hlU=wp+c=?`zNM7Aj!ZohrOP=5VadgRwqx-bPNSS-4hT z#92HMkkWHU5B%Pt6|fD>#uf5?M<34`tJE8dnG6d54q97MPt--~a5e+UneTFKKMHK; zsVi+4=lJ(zkOf>sxqz#GLR-)zVC?7o*7 zW1Fua1Kt*rs3MCT*Lgmg1Pc6EI9{_heVYGBMth07`}B%F)%*(eDGsa9=9nhdpv)Rq zg-HK(M7Z5N;VVFJg+kM=$NAo4a3N%tU;C%%yOBDO2h^)5cOJzKdl{sq;)#GHw2YNoJ+uS&?Znr!4{|u>A+) CvA0?P literal 0 HcmV?d00001 diff --git a/target/classes/com/chantha/jdbc/utils/jwt/JwtRequestFilter.class b/target/classes/com/chantha/jdbc/utils/jwt/JwtRequestFilter.class new file mode 100644 index 0000000000000000000000000000000000000000..2a892fb0838e45f9a55807e2ea7845b964d68c57 GIT binary patch literal 4172 zcmbtX`Ewk_75-Y%YF4X}u>}rZ3}%hN)`1y_jRO)k*s_h~tSw<#5{6u}yY1bPW@na} zULE8hCy*O*+qq9Cq*4_UN{&LvkEAO9NdAaaCHZ=0wAz)|mIx))Y)|*=*RQ|#y<`6Q zpTGVcz+wD8gZnU%#$+!};+ZrqWbibm^y6X=_F_7N8O$1Zwg;E+TpG`3@DY5}z{k?~ zxL*H68g?%VC}vQC?8Rl2^>ifz2XlJwd^lEH#glmd_Bi+&TJYU($@x4&svAiFYt*{n2UiorhSLLD~%v%L%d!cpN zE-F7*w(Q0R>v&!Hi%uX*RBO`2i~hXyrj_Fg4Blv2oeQBwG3#uTD7SV$;dqWZCeS%B zI3v(C=9hT4+wzVl&)2I38C=g}MyYX~$JE z;F;S?emoxcIN{kexjK-avlr|oLKrN#Qdt$HYStM(G=Q8)bc}8)7S@QS+$a~HH&(G7 zZ&cq?@Jjbbx-8fB%GS8+%ChYq56bnb^wg=PqO57Z(Ao#`j&IF{zPBg~N`q{jTB>Q_ ziDa|fzB+C9=(kBb4C%WPJyfACrxvmz%fz?w9RuGr@jZOs#6H|_;0GqI;Hrrq z;ztI4Y~m;QslY_LtoT0S#lX)@{2af~Zuq6Z`CF=I$Xgpia#j{v1ADD5L@Y7!EBxBT zZ}7T_Yxu2+-{B2nbVH?R$;T~(5;)Y(ByGv%D1llNUQtfUV8gBlwv;~w_HQP)7RuRH z!KScen5@$<_N>63R`DclHzG{n_Gk|YH$Krc+e2oqh4ub8d$h#$V7pMygvt(7I7@<& zo$Yo#C(skt3t^NTw9I&0MF(!}m?&D}ntBKAoK6z_>AAV?;g6=~7@D$AXv7nudE zystCi9!;Q|OR&l>+QG)NCJJ-1sG{QdWIF;jLM|#GMW3a6Nm)}#$1@hcpYh!&L1&0o zG9_?yV6c65T?j$ATkzgZt|qW8@gB>hawKcZG1* z?3^2`N#iy+!;h-H{89rt_{YKx_Q-te=I{P!mL1CtbNnj75NC%eVewb+H#Kw};>~Ew zgM4ZQKtB%hX~qJ0h{8Y@9>yc+)SJb>kU|gV-Wl%iSVd@_Vr^Nf{=f?Eyn=_{#;!|QLu8FrWCgC{u90*${Wf-A zx{kYtS8&e?_E1wcy^4D~aB%p+RpdJHCXpM!AspdV^zRt@cs&h5fghp3-N@h`&h5c= zVtp^s9w5$#h~W`p{TOk6isLc%hNrl4j^jy!^E~02CtwTsAYP&LYy7CbibvU!9KjnH z!CN?rzu{N}a1FiGlcwY$7}TOihdH{6ySU>B-xnzPA<7sU?8Fgz^f)zXN4-BZdwa6AoX7=Hw^4GaFXX5IBnqR_#eVRPu@VE lnfW)K#Tm+XQ~x;5;=>&Gb@FKNQ1CcSzI^mN*C5|{;D0vW`gi~U literal 0 HcmV?d00001 diff --git a/target/classes/com/chantha/jdbc/utils/jwt/JwtResponse.class b/target/classes/com/chantha/jdbc/utils/jwt/JwtResponse.class new file mode 100644 index 0000000000000000000000000000000000000000..4886db39e159a169b2c2366f4db117cdf201b880 GIT binary patch literal 626 zcma)(OHLa>5QhI6#x@um90&3sFJ*&lM@nz9OT-3*6y!V<6YtyOmfdDN9nG|ZluK|8 zmY@V7vETq4fMrgQGer4kjFd=hvgvws)!$!rUH!he1n>&astECL2@BY$;86vSD|jMk zWG1yb?wd5TF8Ta+M<9EG`nF3luM^+b@ywKtzW=;F_P;{G;^feKcVH4hvpdmWwTg8z zQazvAWb|54eq$5sw*>30+t=;BAl!CCBUtU)#JrzP2PWOugP56S*F^-;#9@4s4E@+< zf>t+jQx%N~G}dY|97Jm7ZJa66sJ%n~$z)#$YzWYJXZ+X=Kk8IZjptZo9vQzsXI^Wy zZ(|9nJvU1uvuksZ#y^5D^AT&P<7o}cs0lXz4}>azKj*_>Vj?eCD^k{}Uh(Jl+kEha zR=bbq+)D^S2>~`xMuq+&_ZDCY&HU-Y=VGwJ+$y78+JLs&Ifry!oFO8%4qW HqUymP0Sbtt literal 0 HcmV?d00001 diff --git a/target/classes/com/chantha/jdbc/utils/jwt/JwtTokenUtil.class b/target/classes/com/chantha/jdbc/utils/jwt/JwtTokenUtil.class new file mode 100644 index 0000000000000000000000000000000000000000..fc954cdf4def7be71da35c656148e00cc89315d4 GIT binary patch literal 5157 zcmbtXiCY|J8UM|44D3z)m>{wL(a=#(LL!-&*|({1be9{C(dHy92vHeERIOGvE2XzxRIU`Ttyg z7QlY|GmbV)HgRmnaXn^LI89JstGGwZ^9gwH<0#-lJ*RUC+>3efxG#bG@kSL7h*NKh zqZX6m@n9Se;ms=E631ptCh#!cDh|9&Pk0@yL%)DjT<7VEoT<7#)zXD}Q z!G@&kc)sEI9Ukl-Or4Rufq|0>YCSWP zH+>!(o-r;Mx@|a9`k0@$oT+XF+fNl7-16wHZA`5I2k7LkEj!Fm#R$Q>J6myUfsO zN82jKB4ewNxBPiMVJV~Z(Gep@ z`3|gH=?SLM)Du}*wlwcGWZk1HB|i}Av`9R1F%%{m1V#B&uOQ<=!Ck8;tP{*S`D|de zv$7>ir7QTrOHgi9wvzkQ3FC>p#wN;gGQ;yz&{1s#>q zFtM4g&#=~$?rhF=Ovmrma2sx?f0D89`FSH3WJ0f@7LPXKVnaPX)re1P_zWJ?a0CN9 zT5|Tl5j)uGNIt>e0RB=he5-w}F zg72#Mo`z@feIf5v4L`thjOBF}8Vx_hb1HtM;m7!ihM(eR8h$P~y&8u#Jda;!cnwZz zcmcm$p`O6$S*0Xc3O6Q;zIC4{dU5;;zg|_U!YGM4M7Wf|M*KzrvsYyuRZajkMlNU1 zE4Z;OBzcVzBdGtDZu7sW%j;qKYAIQutY%T<)iCL$EUL9RBTu(xxgw$pM_7Ql%_On? znwty<&-6u2Vasydq;z_Pa9o@EMhPRR4MTIH=U68RQ6)E*Ln8&1^`_6w5>E57vZE!A zqNmMCW^mq*<|?Vo_Or_lEw6+*fHY;7H9E=2XgeEqic*%iy;A$Ou9Bf3LCB(p1W9Hk z>{5&ou*o5 zO<>WCHShW6EY;1TnrHq?u`eF6Y+E#*>{;1@SGNs`)-^$%gPvC~v%T!A_eBv0Hml^m zCCI`@OWmV_-K%v|Y>ImADVOzqnxJZqjU9N!tqNMpXqTU+SalwQV1ic_q{<_=!j($p zZZ$5(X-Nu|2{Om80D7-^PrjPQGdx@Ql*JX7%^xevSU`9h9d1|9ZH^drwR3Fd_; zn2=sjzm6GB);7J?;9_^Vc(c|mi3|OvxHyXqt<)mTTW0w3}h%+FIe$MuA zg$Fe)r7Ot^~ zbALbg6MP@w|DcCgp`HWw6MWvmEuC+L@0yN9C{IaR-F(){#ZBnpSPKr|P8{M)5fzox z#pOQYi1EF#WA9}#SU}ZPR6og;7)n&ONh(`|lOYw}L9fKu$I~?mCxSGa2p%gV&Ch5_ zx^^|`>()=2eG$L%e^SR04g8y8cP;eC+R}0=65xk{{tfgG1G12yfd?pC6ihQ|H>^Naq#Qo>@fW0ybSjQ;9<$ ze;cK0mt1xRmx^4rgj{OTfH9;V08B{bvbQ8-q1eZuO6@xjzJ!}oBzN$UeAqlcmpp886M_ac! zNjUJ$3)u50)au7kT@{)!>c%}Zh|Z8W}!g$ja;@a)rtHpZJe+{0ICUe`G$I;#@?%a03f7I3JE&