2017/06/14這一天,是我玩Shiro安全框架最刻骨銘心的一天。因為Shiro今天給我深深的補了一刀,在這兒我也給各位補一刀吧,其實問題很簡單,解決方式也極其簡單,只是給各位分享一下這個錯誤,純屬給各位長點經驗值。
之前自己搭建了一套系統拿來練手,將Shiro請到這套系統中作為了第一道防鎖線,今天閑來無事想加個短信驗證碼上去,就登陸了中國建網,還好,之前玩剩下的還有3條短信,於是就小忙了起來,找到很久以前玩過的SMS短信發送的那段代碼,但是代碼很亂很臟,因為那時候不懂事兒瞎寫的,現在整理了一下我就不客氣了,給大家貼在這兒了,哈哈~~由於這是一段模版代碼,只需把自己在短信平台注冊的用戶名和接口調用的秘匙補上去,還有將你想要發送的隨機驗證碼和短信模板內容告訴接口就OK。
1 public static String sendCode(String url,String encoded,String mobile,String SMSTemplate){ 2 //獲取隨機6位驗證碼
3 String code = VerifyCodeUtils.generateVerifyCode(6); 4 HttpClient client = new HttpClient(); 5 PostMethod post = new PostMethod(url); 6 post.addRequestHeader("Content-Type", "application/x-www-form-urlencoded;charset="+encoded); 7 NameValuePair[] data = { 8 new NameValuePair("Uid", 用戶名), 9 new NameValuePair("Key", 秘匙), 10 new NameValuePair("smsMob", mobile), 11 new NameValuePair("smsText", "驗證碼:"+code+SMSTemplate)}; 12 post.setRequestBody(data); 13 try { 14 client.executeMethod(post); 15 Header[] headers = post.getResponseHeaders(); 16 int statusCode = post.getStatusCode(); 17 System.out.println("statusCode:" + statusCode); 18 for (Header h : headers) { 19 System.out.println(h.toString()); 20 } 21 String result = new String(post.getResponseBodyAsString().getBytes("gbk")); 22 System.out.println(result); // 打印返回消息狀態
23
24 post.releaseConnection(); 25 } catch (Exception e) { 26 e.printStackTrace(); 27 } 28
29 return code; 30 }
需求:用戶登錄要求必須輸入正確的用戶名和密碼,最后還要二次驗證通過,發送短信驗證碼來校驗該用戶是否合法?
需求分析及場景還原:
由於我的登錄功能是通過shiro安全框架來實現的,所以短信驗證碼功能就必須通過發送ajax異步請求后台,將系統發送出去的短信驗證碼保存在了session中,然后在用戶認證過程中取出登錄用戶在頁面輸入的驗證碼對比即可。但是,不幸的是,我不夠老道不夠細心經驗不足,導致shiro讓我圍着它轉了將近一天。點擊按鈕獲取短信驗證碼,在這兒我是通過給按鈕綁定點擊事件來發送ajax請求,后台通過調用上面抽取的工具方法來給指定用戶發送短信內容,邏輯沒錯吧。就這么簡單,為什么我就能玩出302 Found呢,也許大家還不清楚302 Found是什么意思吧?我也不說網上那些繞來繞去的說法,我的理解就是資源存在,但是由於重定向設定權限而導致未正確跳轉至目標鏈接。找了一天資料,學了各種說法,也試了各種方法,但是最后解決問題的是一句出乎意料的簡單配置,下面就給大家把現場布置一下吧,302 Found的奇妙出現,我竟然分析了那么久。
你們不要懷疑我后台代碼寫錯了或是前端代碼寫錯了,沒有的事兒。當我一點擊按鈕ajax方法不執行,在瀏覽器中打斷點各種嘗試走到發送ajax的那段代碼就跳過去,請求也不發,后台代碼肯定也不執行,為啥,難道我前端js代碼寫錯了?不會啊,昨天還剛把異步加載菜單的那玩意兒給搞出來了,js代碼寫了一整天也沒出什么意外,今天就寫這么幾行簡單的js代碼不會太過分吧。於是就各種打斷點各種分析,我這個人吧,在開發中只要是我代碼的執行邏輯沒問題,我就會把他測試到爛也得把問題找出來,行這次我輸,實在是耗不起啊,也不是太大的問題,就這么耗着不值得。叫師兄過來看看吧,也許當局者迷,他過來也是一頓斷點各種走流程,沒錯啊你這咋回事啊,奇了怪了~~~我看他也被這看似正常內藏大坑的代碼搞無語了,我就說行吧,我再自個兒琢磨一下吧,你先把你的活干了。
接着我又趴在桌子上想啊想啊,登錄能正常調用,我發送個ajax不至於這么絕吧,一杯水下肚,巧了,Shiro在跟我開玩笑呢,你利用了我,就得時刻注意我的一舉一動,原來我是把發送短信驗證碼的方法給攔截了,哎吆我滴孩啊,這種錯誤不是技術惹的禍,而是你就踩過這坑沒,只要你玩過這功能玩過這樣的業務,你就會,其實我才在IT界混了短短2年多,哪有那么深的手法啊,在這里我不是繞圈子給大家炫我做的功能,而是想給大家分享這種錯誤,我希望讀到這篇博文的朋友有個印象,以后遇到足夠你裝了,瞬間解決問題,咱們這行不就是拿經驗混飯吃嘛。
解決方式:配置忽略項。在spring管理Shiro安全框架的配置文件中配置獲取驗證碼的方法,讓它可以匿名訪問即可,就是用戶沒有登錄,也可以發送請求到后台執行方法。
1 <!-- shiro連接約束配置 -->
2 <property name="filterChainDefinitions">
3 <value>
4 <!-- 對靜態資源設置允許匿名訪問 -->
5 /images/** = anon 6 /js/** = anon 7 /css/** = anon 8 <!-- 可匿名訪問路徑,例如:短信驗證碼、登錄連接、退出連接等 -->
9 /auth/login = anon 10 /user/sendCode = anon 11 <!-- 剩余其他路徑,必須認證通過才可以訪問 -->
12 /** = authc 13 </value>
14 </property>
最后提醒大家,以后用到安全框架,就請善待它,這種錯誤你是學不到的,只有下過坑才能嘗到那種美味。