學習目標
如標題有如下兩個功能實現(xiàn):
記住我的功能:通過設(shè)置key為“rememberMe”的cookie保存在客戶端來完成記住我的功能,下次用戶訪問指定頁面時就不會重新登錄,一直到cookie過期后才會重新登錄。
-
GIF格式驗證碼:
,這個要感謝sojson的博主對這個GIF驗證碼插件的實現(xiàn)。
此項目下載地址:https://git.oschina.net/z77z/springboot_mybatisplus
記住我
- ShiroConfig的配置:
在ShiroConfig.java中添加如下方法:
/**
* cookie對象;
* @return
*/
public SimpleCookie rememberMeCookie(){
//這個參數(shù)是cookie的名稱,對應前端的checkbox的name = rememberMe
SimpleCookie simpleCookie = new SimpleCookie("rememberMe");
//<!-- 記住我cookie生效時間30天 ,單位秒;-->
simpleCookie.setMaxAge(2592000);
return simpleCookie;
}
/**
* cookie管理對象;記住我功能
* @return
*/
public CookieRememberMeManager rememberMeManager(){
CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();
cookieRememberMeManager.setCookie(rememberMeCookie());
//rememberMe cookie加密的密鑰 建議每個項目都不一樣 默認AES算法 密鑰長度(128 256 512 位)
cookieRememberMeManager.setCipherKey(Base64.decode("3AvVhmFLUs0KTA3Kprsdag=="));
return cookieRememberMeManager;
}
rememberMeCookie()方法是設(shè)置Cookie的生成模版,比如cookie的name,cookie的有效時間等等。
rememberMeManager()方法是生成rememberMe管理器,而且要將這個rememberMe管理器設(shè)置到securityManager中,如下:
@Bean
public SecurityManager securityManager() {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
// 設(shè)置realm.
securityManager.setRealm(myShiroRealm());
// 自定義緩存實現(xiàn) 使用redis
securityManager.setCacheManager(cacheManager());
// 自定義session管理 使用redis
securityManager.setSessionManager(SessionManager());
//注入記住我管理器;
securityManager.setRememberMeManager(rememberMeManager());
return securityManager;
}
其實上面的步驟,也就是rememberMe管理器可以不用配置,shiro會使用默認的配置,之所以要配置的目的是為了能夠在實際業(yè)務環(huán)境中自定義其中的參數(shù)。
- 登錄controller的改造
@RequestMapping(value="ajaxLogin",method=RequestMethod.POST)
@ResponseBody
public Map<String,Object> submitLogin(String username, String password,Boolean rememberMe,Model model) {
Map<String, Object> resultMap = new LinkedHashMap<String, Object>();
try {
UsernamePasswordToken token = new UsernamePasswordToken(username, password,rememberMe);
SecurityUtils.getSubject().login(token);
resultMap.put("status", 200);
resultMap.put("message", "登錄成功");
} catch (Exception e) {
resultMap.put("status", 500);
resultMap.put("message", e.getMessage());
}
return resultMap;
}
之前我是將shiro已經(jīng)實現(xiàn)的UsernamePasswordToken類再封裝了一層,最后發(fā)現(xiàn)沒有必要,直接使用shiro提供的UsernamePasswordToken的類,其中有一個構(gòu)造函數(shù)需要傳rememberMe這個參數(shù),也就是shiro為我們已經(jīng)實現(xiàn)好了,推薦大家去看下UsernamePasswordToken這個類的源碼。
- jsp頁面的改造
<!DOCTYPE html>
<%@ page language="java" contentType="text/html; charset=utf-8"
pageEncoding="utf-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme() + "://"
+ request.getServerName() + ":" + request.getServerPort()
+ path;
%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<script type="text/javascript"
src="<%=basePath%>/static/js/jquery-1.11.3.js"></script>
<title>登錄</title>
</head>
<body>
錯誤信息:
<h4 id="erro"></h4>
<form>
<p>
賬號:<input type="text" name="username" id="username" value="admin" />
</p>
<p>
密碼:<input type="text" name="password" id="password" value="123" />
</p>
<P><input type="checkbox" name="rememberMe" id="rememberMe" />記住我</P>
<p>
<input type="button" id="ajaxLogin" value="登錄" />
</p>
</form>
</body>
<script>
$(function(){
$("#ajaxLogin").click(function() {
var username = $("#username").val();
var password = $("#password").val();
var rememberMe =$('#rememberMe').is(':checked');
$.post("/ajaxLogin", {
"username" : username,
"password" : password,
"rememberMe" : rememberMe
}, function(result) {
if (result.status == 200) {
location.href = "/index";
} else {
$("#erro").html(result.message);
}
});
});
});
</script>
</html>
添加一個記住我的單選框,來控制是否需要記住我。
- 修改權(quán)限配置,修改sys_permission_init表
因為getGifCode是獲取驗證碼的鏈接,所以要配置為anon,不需要權(quán)限驗證。user權(quán)限是配置記住我或認證通過可以訪問,所以將/**鏈接設(shè)置為user權(quán)限,就可以實現(xiàn)記住我的功能。
注意權(quán)限添加的排序。
GIF驗證碼
- 編寫一個獲取GIF驗證碼圖片的controller:
/**
* 獲取驗證碼(Gif版本)
* @param response
*/
@RequestMapping(value="getGifCode",method=RequestMethod.GET)
public void getGifCode(HttpServletResponse response,HttpServletRequest request){
try {
response.setHeader("Pragma", "No-cache");
response.setHeader("Cache-Control", "no-cache");
response.setDateHeader("Expires", 0);
response.setContentType("image/gif");
/**
* gif格式動畫驗證碼
* 寬,高,位數(shù)。
*/
Captcha captcha = new GifCaptcha(146,33,4);
//輸出
captcha.out(response.getOutputStream());
HttpSession session = request.getSession(true);
//存入Session
session.setAttribute("_code",captcha.text().toLowerCase());
} catch (Exception e) {
System.err.println("獲取驗證碼異常:"+e.getMessage());
}
}
生成驗證碼后,將圖片返回到頁面,將字符串保存在當前會話的session域中。
這個GIF驗證碼的生成插件源碼在我的項目io.z77z.vcode這個包下面,大家需要的話可以在我的碼云上去下載。
- 改造登錄controller:
/**
* ajax登錄請求
* @param username
* @param password
* @return
*/
@RequestMapping(value="ajaxLogin",method=RequestMethod.POST)
@ResponseBody
public Map<String,Object> submitLogin(String username, String password,String vcode,Boolean rememberMe,Model model) {
Map<String, Object> resultMap = new LinkedHashMap<String, Object>();
if(vcode==null||vcode==""){
resultMap.put("status", 500);
resultMap.put("message", "驗證碼不能為空!");
return resultMap;
}
Session session = SecurityUtils.getSubject().getSession();
//轉(zhuǎn)化成小寫字母
vcode = vcode.toLowerCase();
String v = (String) session.getAttribute("_code");
//還可以讀取一次后把驗證碼清空,這樣每次登錄都必須獲取驗證碼
//session.removeAttribute("_come");
if(!vcode.equals(v)){
resultMap.put("status", 500);
resultMap.put("message", "驗證碼錯誤!");
return resultMap;
}
try {
UsernamePasswordToken token = new UsernamePasswordToken(username, password,rememberMe);
SecurityUtils.getSubject().login(token);
resultMap.put("status", 200);
resultMap.put("message", "登錄成功");
} catch (Exception e) {
resultMap.put("status", 500);
resultMap.put("message", e.getMessage());
}
return resultMap;
}
登錄的時候判斷前臺傳入的驗證碼和session中的是否一致。
- 前端jsp頁面改造
<!DOCTYPE html>
<%@ page language="java" contentType="text/html; charset=utf-8"
pageEncoding="utf-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme() + "://"
+ request.getServerName() + ":" + request.getServerPort()
+ path;
%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<script type="text/javascript"
src="<%=basePath%>/static/js/jquery-1.11.3.js"></script>
<title>登錄</title>
</head>
<body>
錯誤信息:
<h4 id="erro"></h4>
<form>
<p>
賬號:<input type="text" name="username" id="username" value="admin" />
</p>
<p>
密碼:<input type="text" name="password" id="password" value="123" />
</p>
<p>
驗證碼:<input type="text" name="vcode" id="vcode"/>
</p>
<p>

</p>
<P><input type="checkbox" name="rememberMe" id="rememberMe" />記住我</P>
<p>
<input type="button" id="ajaxLogin" value="登錄" />
</p>
</form>
</body>
<script>
$(function(){
$("#ajaxLogin").click(function() {
var username = $("#username").val();
var password = $("#password").val();
var vcode = $("#vcode").val();
var rememberMe =$('#rememberMe').is(':checked');
$.post("/ajaxLogin", {
"username" : username,
"password" : password,
"vcode" : vcode,
"rememberMe" : rememberMe
}, function(result) {
if (result.status == 200) {
location.href = "/index";
} else {
$("#erro").html(result.message);
}
});
});
});
</script>
</html>
總結(jié):
到此,我們集成shiro和redis,學習了一下功能的實現(xiàn):
- 用戶必須要登陸之后才能訪問定義鏈接,否則跳轉(zhuǎn)到登錄頁面,被禁用戶不能登錄。并且對一些敏感操作鏈接設(shè)置權(quán)限,只有滿足權(quán)限的才可以訪問。
- 每個鏈接的權(quán)限信息保存在數(shù)據(jù)庫,可以動態(tài)進行設(shè)置,并且熱加載權(quán)限。
- 使用redis對shiro的用戶信息進行緩存,不用每次都去執(zhí)行MyShiroRealm.doGetAuthorizationInfo()權(quán)限認證方法。
- 之前有很多同學下載我的項目時,運行會報錯,那是因為最近都在不斷修改提交,有可能會出現(xiàn)版本問題,現(xiàn)在我在我的碼云上面創(chuàng)建了stable_version分支,都是可以跑起來的。sqltable放在resource目錄下面。
- “記住我”的功能,利用cookie。
- GIF驗證碼的生成,在登陸時進行驗證碼的校驗。利用session。
- 下一博,我應該會寫對在線用戶的管理,踢出登錄的功能學習記錄。
香蕉硬幣點贊走一波啦。。。。。。