Artikel ini memperkenalkan metode Spring-Boot dikombinasikan dengan Shrio untuk mengimplementasikan JWT, dan membagikannya kepada Anda, sebagai berikut:
Mengenai verifikasi, ada kira -kira dua aspek:
Solusi Utama: Gunakan filter Shiro khusus
Konstruksi Proyek:
Ini adalah proyek web Spring-Boot. Jika Anda tidak tahu tentang konstruksi proyek Spring-Boot, silakan Google.
pom.mx memperkenalkan paket toples terkait
<!-Manajemen Izin Shiro-> <dependency> <groupid> org.apache.shiro </proveDid> <Artifactid> Shiro-SPRING </arttifactid> <version> $ {shiro.version} </version> <deplendency> <dependency> <groupid> org.apache.shiro </Version> <sgelency> <groupid> <groupid> org.apache.shiro </versi <version> $ {shiro.version} </version> </dependency> <!-jwt-> <dependency> <groupid> io.jsonwebtoken </sroupid> <ArtifactId> jjwt </arttifactid> <version> 0.9.0 </version> </dependensi> Konfigurasi Terkait Shrio
Buatlah intinya! Lai Menyesuaikan filter
filtermap.put ("jwtfilter", jwtfilter baru ()); @ConfigurationPublic kelas ShiroConfig {@Bean Publik ShirofilterFactoryBean GetshirofilterfactoryBean (SecurityManager SecurityManager) {shirofilterfactorybean ShirofilterfactoryBean = baru shirofilterfactorybean (); shirofilterfactorybean.setsecurityManager (SecurityManager); // Tambahkan filter Anda sendiri dan beri nama peta jwtfilter <string, filter> filtermap = new HashMap <> (); filtermap.put ("jwtfilter", jwtfilter baru ()); shirofilterfactorybean.setFilters (filtermap); / * * Aturan URL Kustom * http://shiro.apache.org/web.html#urls- */peta <string, string> filterChainDefinitionMap = shirofilterfactorybean.getFilterChainDefinitionMap (); filterChainDefinitionMap.put ("/**", "jwtfilter"); shirofilterfactorybean.setfilterchaindefinitionMap (filterchainDefinitionMap); kembalikan shirofilterfactorybean; }/** * SecurityManager tidak perlu menyuntikkan shirodbrealm secara langsung, yang dapat menyebabkan kegagalan transaksi * untuk solusinya, lihat HandlecontExtrefresh * http://www.debugrun.com/a/nks9ejq.html */@bean ("SecurityManager") Public DefaudeRMLMLAUREBE ("SecurityManager") PUBLICEDMANCEUREBE ("SecurityManager") Publik DefaultWebSecurityManager Manager = New DefaultWebSecurityManager (); Manager.setrealm (TokenRealm); / * * Tutup sesi yang disertakan dengan Shiro, lihat dokumentasi untuk detailnya * http://shiro.apache.org/session-management.html#sessionManagement-statelessApplications%28Session netesly%29 */defaultSubjectDao SubjekDao = new DefaultSubjectDAo (); DefaultSessionStorageEvaluator DefaultSessionStorageEvaluator = New DefaultSessionStorageEvaluator (); DefaultSessionStorageEvaluator.SetsessionStorageEnabled (false); Subjectdao.setsessionStorageEvaluator (defaultSessionStorageEvaluator); manajer.setsubjectdao (subjekdao); manajer kembali; } @Bean Public LifeCycleBeanPostProcessor LifeCycleBeanPostProcessor () {return baru LifeCycleBeanPostProcessor (); } @Bean (name = "tokenRealm") @Dependson ("LifeCycleBeanPostProcessor") TokenRealm publik TokenRealm () {return new TokenRealM (); } @Bean @dependson ("LifeCycleBeanPostProcessor") Public DefaultAdvisorAutOproxyCreator DefaultAdvisorAutOproxyCreator () {defaultAdvisorAutoproxyCreator DefaultAdcroator () {DefaultRisorApArdCreator (New DefaultApArdCreator (DefaultApArdCreator (DEFAULADREATRICREAT (DEFAULACROCREAT (DEFAULACROUT (DEFAULADREATOR (DEFAULACARACROUT (DEFAULADREATOR (DEFAULADREATRICREAT (DEFAULACROCREAT (DEFAULACROCREAT ( // paksa cglib untuk mencegah proxy duplikat dan kemungkinan kesalahan proxy // https://zhuanlan.zhihu.com/p/29161098 defaultAdvisorAutoproxycreator.setproxytargetclass (true); return defaultAdvisorAutoproxycreator; } @Bean Public AuthorizationAttributeSourCeadVisor GetAuthorizationAttributSourCeadVisor (SecurityManager SecurityManager) {OtorisasiTributeSourCeadVisor OtorisasiTattributeSourCeAdvisor = Otorisasi baruTributSourceadVisor (); OtorisasiTributSourceadVisor.SetsecurityManager (SecurityManager); mengembalikan otorisasi baru yang bersambung (); }} Kustomisasi Filter Shrio
Pesanan Eksekusi: Prehandle -> Dofilterinternal -> ExecuteLogin -> Onloginsuccess
Penilaian utama adalah apakah permintaan login adalah dofilterinternal
Kelas Publik JWTFilter Memperluas BasichttPAuthenticationFilter { / *** Kustomisasi metode untuk mengeksekusi login* / @Override yang dilindungi boolean executelogin (permintaan servletRequest, httpservleter httpservlete {httpservletequest) (httpservletequest httpservlete = httpservletequest httpservlete {httpservlet UsernamepasswordToken usernamepasswordtoken = json.parseObject (httpservletrequest.getInputStream (), usernamepasswordtoken.class); // Kirimkan ke ranah untuk login. Jika kesalahannya salah, itu akan melempar pengecualian dan ditangkap subjek subjek = this.getSubject (permintaan, respons); subjek.login (usernamepasswordtoken); kembalikan ini. // Kesalahan melempar pengecualian}/ *** Metode pertama untuk mengeksekusi*/ @Override Protected Boolean Prehandle (permintaan servletRequest, respons servletResponse) melempar pengecualian {return super.prehandle (permintaan, respons); } / *** Operasi login Setelah login yang berhasil* Tambahkan header JWT* / @Override Protected Boolean OnlogInccess (AuthenticationToken Token, Subjek, Permintaan ServletRequest, ResponseResponse Upponse) {httpservletsePonse httpservleteRespons = (httpservletserponse) htponServleteSpons = (htttpserv; String jwttoken = jwts.builder () .setId (token.getPrincipal (). ToString ()) .setExpiration (datetime.now (). Plusminutes (30) .todate ()) .Signwith (SignaturealgorityM.hs256, Jwtcost. httpservletresponse.addheader (otorisasi_header, jwttoken); Kembali Benar; } /** * The main process of login and verification* Determine whether it is login, or an ordinary request after login*/ @Override public void doFilterInternal(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { HttpServletRequest httpServletRequest = (Httpservletrequest) servletRequest; HttpservletResponse httpservletResponse = (httpservletResponse) servletResponse; String servletpath = httpservletRequest.getServerPath (); if (stringutils.equals (servletpath, "/login")) {// executelogin (servletRequest, servletResponse); } else {string authenticationHeader = httpservletRequest.getHeader (otorization_header); if (stringutils.isnotempty (authenticationHeader)) {klaim body = jwts.parser () .setsigningKey (jwtcost.signatureKey) .parseclaimsjws (authenticationHeader) .getBody (); if (body! = null) {// Perbarui token body.setExpiration (datetime.now (). Plusminutes (30) .todate ()); String updateToken = jwts.builder (). SetClaims (body) .compact (); httpservletResponse.addheader (otorisasi_header, updateToken); // Tambahkan Kredensial Pengguna PrincipalCollection Principals = new SimplePrincipAlcollection (body.getId (), jwtcost.usernamepasswordRealm); // rakitkan informasi pengguna shiro websubject.builder builder = new WebSubject.builder (servletRequest, servletresponse); builder.principals (kepala sekolah); builder.authenticated (true); builder.SessionCreationEnabled (false); Subjek WebSubject = Builder.BuildWebsubject (); // dimasukkan ke dalam wadah dan hubungi threadContext.bind (subjek); filterchain.dofilter (httpservletrequest, httpservletResponse); }} else {httpservletResponse.setStatus (httpstatus.forbidden.value ()); }}}} Login gagal diproses
Menangani pengecualian Shrio
@RestControllerAdvicepublic kelas GlobalControllerExceptionHandler {@ExceptionHandler (value = Exception.class) Objek Publik AllexceptionHandler (httpservletRequest Request, httpservletResponse respons, pengecualian) {string message = exception.getCause (). Logutil.error (pesan); kembalikan hasil baru (exception.getClass (). getName (), pesan); } /*============ Shiro Exception Intercept ==========================* / @ExceptionHandler (nilai = tidak ada lagi, httpservletception. response.setstatus (httpstatus.forbidden.value ()); return "InrectCredentialSexception"; } @ExceptionHandler (value = UnknownAccountException.class) Public String UnknownAccountException (permintaan httpservletRequest, respons httpservletResponse, pengecualian pengecualian) {response.setstatus (httpstatus.forbidden.value ()); return "UnknownAccountException"; } @ExceptionHandler (value = LockEdAccountException.class) Public String LockEdAccountException (permintaan httpservletRequest, respons httpservletResponse, pengecualian pengecualian) {response.setstatus (httpstatus.forbidden.value ()); mengembalikan "LockEdAccountException"; } @ExceptionHandler (value = ExcessIveAttemptSException.class) Public String ExcessIveAtemplSException (httpservletRequest, respons httpservletResponse, pengecualian pengecualian) {response.setstatus (httpstatus.forbidden.value ()); kembalikan "ExcessIveAtemplSException"; } @ExceptionHandler (value = AuthenticationException.class) Public String AuthenticationException (httpservletRequest, respons httpservletResponse, pengecualian pengecualian) {response.setStatus (httpstatus.forbidden.value ()); mengembalikan "AuthenticationException"; } @ExceptionHandler (value = unkorizedException.class) Public String UnrorizedException (permintaan httpservletRequest, respons httpservletResponse, pengecualian pengecualian) {response.setstatus (httpstatus.forbidden.value ()); mengembalikan "Exhorized Exception"; }}Menangani pengecualian JWT
Ini adalah jebakan, karena ini adalah pengecualian yang terjadi di filter, dan @ExceptionHandler tidak dapat mencegatnya.
/*** Intercept Spring Boot Error Page*/ @restControllerPublic kelas GlobalExceptionHandler mengimplementasikan errorController {@Override public string getErrorPath () {return "/error"; } @RequestMapping (value = "/error") Kesalahan objek publik (permintaan httpservletrequest, respons httpservletResponse) melempar pengecualian {// kesalahan penanganan logika pengecualian Logika exception = (pengecualian) request.getattribute ("javax.servlet.error. exception"); Penyebab yang dapat dilewati = Exception.getCause (); if (penyebab instance dari exiredjwtexception) {response.setStatus (httpstatus.gateway_timeout.value ()); return new resultInfo ("ExpiredJwtException", Cause.getMessage ()); } if (Cause Instanceof MalformedjWtException) {response.setStatus (httpstatus.forbidden.value ()); return new resultInfo ("MalformedjwtException", cause.getMessage ()); } return new resultInfo (cause.getCause (). getMessage (), cause.getMessage ()); }}Mengenai informasi otorisasi seperti izin, Anda dapat langsung memasukkannya ke Redis ke cache. Saya pikir itu bagus juga.
Kode sumber menyajikan: Githup-Shiro Cabang: Pengingat Hangat: Kode tes mungkin berantakan dalam kehidupan sehari-hari.
Di atas adalah semua konten artikel ini. Saya berharap ini akan membantu untuk pembelajaran semua orang dan saya harap semua orang akan lebih mendukung wulin.com.