تقدم هذه المقالة طريقة spring-boot مع Shrio لتنفيذ JWT ، ومشاركتها معك ، على النحو التالي:
فيما يتعلق بالتحقق ، هناك جانبان تقريبًا:
الحل الرئيسي: استخدم مرشح شيرو مخصص
بناء المشروع:
هذا هو مشروع ويب الربيع. إذا كنت لا تعرف بناء مشروع SPRING-Boot ، فيرجى Google.
POM.MX يقدم حزم جرة ذات صلة
<!-إدارة الإذن Shiro-> <redency> <roupiD> org.apache.shiro </groupid> <StifactId> shiro-spring </stifactid> <splement> $ {shiro.version} </sperive> <sophy> $ {shiro.version} </version> </sependency> <!-jwt-> <reperence> <roupiD> io.jsonwebtoken </rougeid> <StifactId> jjwt </shintifactid> <الإصدار> 0.9.0 </version> </empendency> التكوين المتعلق بـ Shrio
جعل هذه النقطة! ! تخصيص مرشح
filtermap.put ("jwtfilter" ، new jwtfilter ()) ؛ ConfigurationPublic Class Shiroconfig {bean public Shirofilterfactorybean getShirofactorybean (SecurityManager SecurityManager) {Shirofilterfactorybean shirofilterfactorybean = new ShirofilterfactoriBean () ؛ Shirofilterfactorybean.SetSecurityManager (SecurityManager) ؛ // أضف مرشحك الخاص وتسميه jwtfilter خريطة <string ، filter> filtermap = new hashmap <> () ؛ filtermap.put ("jwtfilter" ، new jwtfilter ()) ؛ shirofilterfactorybean.setFilters (filtermap) ؛ / * * قواعد url مخصصة * http://shiro.apache.org/web.html#urls- */map <string ، string> filterchaindefinitionmap = shirofilterfactorybean.getFilterChainDefinitionMap () ؛ FilterChainDefinitionMap.put ("/**" ، "jwtfilter") ؛ shirofilterfactorybean.setFilterChainDefinitionMap (FilterChainDefinitionMap) ؛ إرجاع shirofilterfactorybean ؛ }/** * لا يحتاج SecurityManager إلى ضخ shirodbrealm مباشرة ، مما قد يتسبب في فشل المعاملة * بالنسبة للحل ، انظر HandleContextrefresh * http://www.debugrun.com/a/nks9ejq.html */bean ( {defaultWebSecurityManager Manager = New DefaultWebSecurityManager () ؛ manager.setRealm (tokenrealm) ؛ / * * أغلق الجلسة التي تأتي مع Shiro ، راجع الوثائق للحصول على التفاصيل * http://shiro.apache.org/session-management.html#sessionmanmance-statelessedabplications٪28sessionless٪29 */defaultsubjectdao tabledao = new defaultsubjectdao () ؛ DefaultSessionStoreValuator DefaultSessionStoreValuator = New DefaultSessionStorageValuator () ؛ DefaultSessionStorageValuator.SetSessionStoreNabled (false) ؛ TonferDao.SetSessionStoreValuator (DefaultSessionStorageValuator) ؛ manager.setsubjectdao (thisionDao) ؛ مدير العودة ؛ } Bean Public LifecycleBeanPostProcessor LifecycleBeanPostProcessor () {return New LifecyCleBeanPostProcessor () ؛ } bean (name = "tokenrealm") dependson ("LifecyCleBeanPostProcessor") tokenrealm public tokenrealm () {return new tokenrealm () ؛ } beandependson ("LifecyClebeanPostProcessor") Public DefaultAdvisorautOproxyCreator defaultAdvisorautOproxyCreator () {defaultAdvisorautOproxyCreator defaultAdvisorautoproxyCreator = new defaultAdvAdaDoRaeRxyCreator () ؛ // قوة CGLIB لمنع الوكيل المكررة وأخطاء الوكيل المحتملة // https://zhuanlan.zhihu.com/p/29161098 DefaultAdvisorautoproxycreator.setproxytargetClass (True) ؛ إرجاع DefaultAdvisorautoproxyCreator ؛ } bean publicizationattributesourceadvisor getAuthorizationAtributesourCeadVisor (SecurityManager SecurityManager) {eleventizettributesourceadvisor uputristributesourceadvisor = new cuthorizationattributesourceadvisor () ؛ EantaLyatTributesourCeadVisor.SetSecurityManager (SecurityManager) ؛ إرجاع ترخيص جديد computtributesourceadvisor () ؛ }} تخصيص مرشح Shrio
أمر التنفيذ: prehandle -> dofilterinternal -> evelopeLogin -> onloginsuccess
الحكم الرئيسي هو ما إذا كان طلب تسجيل الدخول هو dofilterinternal
يمتد jwtfilter من الفئة العامة basichttpauthenticationfilter { / *** تخصيص طريقة تنفيذ تسجيل الدخول* / Override المحمي المنطقي المنطقي (طلب servletRequest ، استجابة servletResponse) reorhrows ioexception {httpservledrequest httpletrequest = usernamepasswordtoken usernamepasswordtoken = json.parseObject (httpservletrequest.getInputStream () ، usernamepasswordtoken.class) ؛ // إرسالها إلى عالم لتسجيل الدخول. إذا كان الخطأ خاطئًا ، فسوف يلقي استثناءً ويتم اكتشافه موضوعًا = this.getSubject (طلب ، استجابة) ؛ thision.login (usernamepasswordtoken) ؛ إرجاع this.onloginsuccess (usernamepasswordtoken ، الموضوع ، الطلب ، الاستجابة) ؛ . } / *** عملية تسجيل الدخول بعد تسجيل الدخول الناجح* أضف رأس JWT* / Override المحمي Boolean Onloginsuccess (AuthenticationToken Token ، موضوع ServletRequest ، استجابة ServleTResponse) {httpservletResponse httpservletsponse = (httpservervensponse) ؛ String jwttoken = jwts.builder () .setId (token.getPrincipal (). httpservletresponse.addheader (Eutlization_header ، jwttoken) ؛ العودة صحيح. } / *** العملية الرئيسية لتسجيل الدخول والتحقق* تحديد ما إذا كان تسجيل الدخول ، أو طلبًا عاديًا بعد تسجيل الدخول* / Override public void dofilterinternal (servletrequest servletrequest ، servleTResponse ServletResponse ، filterChain filterchain) trows ioexception ، servlexpication {htttpserquesterquesterquesterquest (httpservletrequest) servletRequest ؛ httpservletresponse httpservletresponse = (httpservletresponse) servletResponse ؛ String servletpath = httpservletrequest.getServletPath () ؛ if (stringUtils.equals (servletpath ، "/login")) {// evelodelogin (servletRequest ، servletResponse) ؛ } else {String antainticationHeader = httpservletrequest.getheader (uputization_header) ؛ if (stringUtils.isnotempty (antainticationheader)) {ادعاء الجسم = jwts.parser () .SetSigningKey (jwtcost.signatekey) .parseclaimsjws (HoundicationHeader) .getBody () ؛ if (body! = null) {// تحديث token body.setExpiration (dateTime.Now (). plusMinutes (30) .Todate ()) ؛ String updateToken = jwts.builder (). setClaims (body) .compact () ؛ httpservletresponse.addheader (Authorization_header ، updateToken) ؛ // إضافة بيانات اعتماد المستخدم الرئيسية المدارس = جديد SimplePrincipalCollection (body.getID () ، jwtcost.usernamepasswordrealm) ؛ // تجميع معلومات مستخدم Shiro websubject.builder builder = websubject.builder (servletrequest ، servletResponse) ؛ builder.principals (المدارس) ؛ Builder.Aunitedicated (صحيح) ؛ Builder.SessionCreationEnabled (false) ؛ موضوع websubject = builder.buildWebWebsject () ؛ // ضع في الحاوية واتصل threadContext.bind (الموضوع) ؛ filterchain.dofilter (httpservletrequest ، httpservletresponse) ؛ }} آخر {httpservletresponse.setStatus (httpstatus.forbidden.value ()) ؛ }}}} فشل تسجيل الدخول في المعالجة
التعامل مع استثناءات Shrio
RestControllerAdvicePublic Class GlobalControllexceptionHandler {exceptionHandler (value = issecent.class) كائن عام AllexceptionHandler (httpservletrequest طلب ، httpservletresponse ، استثناء استثناء) {string message = stispion.getCause (). getMessage () ؛ logutil.error (رسالة) ؛ إرجاع new ResultInfo (استثناء. getClass (). getName () ، رسالة) ؛ } /*====تار Response.setStatus (httpstatus.forbdden.value ()) ؛ إرجاع "غير محتملة". } exceptionHandler (value = unknownaccountexception.class) سلسلة عامة غير معروفة unknowcountexception (طلب httpservletrequest ، httpservletresponse ، استثناء استثناء) {response.setStatus (httpstatus.forbidden.value ()) ؛ إرجاع "UnknownAccountexception" ؛ } exceptionHandler (value = lockedAccountexception.class) السلسلة العامة LockedAccountexception (طلب httpservletrequest ، httpservletresponse ، استثناء استثناء) {response.setStatus (httpstatus.forbidden.value ()) ؛ إرجاع "LockedAccountexception" ؛ } exceptionHandler (value = vereviveTeptSeptSexception.class) السلسلة العامة الزائدة إرجاع "الزائد extemptsexception" ؛ } exceptionHandler (value = AuthenticationException.class) antructionException intervication (httpservletrequest ، استجابة httpservletresponse ، استثناء استثناء) {response.setStatus (httpstatus.forbidden.value ()) ؛ إرجاع "AuthenticationException" ؛ } exceptionHandler (value = unauthorizedexception.class) السلسلة العامة غير التراجعية (طلب httpservletrequest ، استجابة httpservletresponse ، استثناء استثناء) {reponse.setStatus (httpstatus.forbidden.value ()) ؛ إرجاع "غير مصرح به من قبل" ؛ }}التعامل مع استثناءات JWT
هذا هو مأزق ، لأنه استثناء يحدث في المرشح ، ولا يمكن لـ exceptionHandler اعتراضه.
/*** Intercept Spring Boot Error Page*/ @restControllerPublic Class GlobalExceptionler تنفذ ErrorController {Override public geterrorpath () {return "/error" ؛ } @requestmapping (value = "/error") خطأ الكائن العام (طلب httpservletrequest ، استجابة httpservletresponse) يلقي استثناء {// خطأ معالجة المنطق استثناء = (استثناء) request.getAttribute ("javax.servlet.error.exception") ؛ سبب رمي = استثناء. getCause () ؛ if (exate extoryof EpiredJwTexception) {response.setStatus (httpstatus.gateway_timeout.value ()) ؛ إرجاع نتائج جديدة ("ExpiredJwTexception" ، cause.getMessage ()) ؛ } if (cause extorlyof malformedjwtexception) {response.setStatus (httpstatus.forbidden.value ()) ؛ إرجاع نتائج جديدة ("malformedjwtexception" ، cause.getMessage ()) ؛ } إرجاع new resultInfo (cause.getCause (). getMessage () ، cause.getMessage ()) ؛ }}فيما يتعلق بمعلومات التفويض مثل الأذونات ، يمكنك وضعها مباشرة في Redis على ذاكرة التخزين المؤقت. أعتقد أنه جيد أيضًا.
يعرض رمز المصدر: Githup-Shiro الفرع: تذكير دافئ: قد يكون رمز الاختبار فوضويًا في الحياة اليومية.
ما سبق هو كل محتوى هذه المقالة. آمل أن يكون ذلك مفيدًا لتعلم الجميع وآمل أن يدعم الجميع wulin.com أكثر.