Shiro自定義realm實現密碼驗證及登錄、密碼加密註冊、修改密碼的驗證
一:先從登錄開始,直接看代碼
@RequestMapping(value="dologin",method = {RequestMethod.GET, RequestMethod.POST},produces="text/html;charset=UTF-8")
@ResponseBody
public ResultJson systemUserdologin(XXX xxx,HttpServletRequest request,HttpServletResponse response, Model model) {
logger.info("=================dologin==============");
response.setHeader("Access-Control-Allow-Origin","*");//跨域
String msg=null ;
Subject currentuser = SecurityUtils.getSubject();
CustomizedToken token = new CustomizedToken(user.getUsername(),user.getUserpassword(),ADMIN_LOGIN_TYPE);//設置多realm驗證的type
try {
if(!currentuser.isAuthenticated()){
// 指明登錄類型為管理員登錄(在授權時使用)
currentuser.getSession().setAttribute("loginType", ADMIN_LOGIN_TYPE);
//將管理員姓名保存到session中,方便在前台使用
currentuser.getSession().setAttribute("userName",xxx.getname());
token.setRememberMe(xxx.isRememberMe());
currentuser.login(token);//開始認證
if (currentuser.isAuthenticated()) {
logger.info("=================認證成功==============");
request.getSession().setAttribute("xxx",xxx);
user.setUserstatus(2);//設置用户登錄狀態為已登錄
SavedRequest savedRequest = WebUtils.getSavedRequest(request);
// 獲取保存的URL
if (savedRequest == null || savedRequest.getRequestUrl() == null) {
return new ResultJson(true, "身份認證成功,跳轉到主頁面", "");
} else {
return new ResultJson(true, "身份認證成功,跳轉到主頁面", "");
}
} else {
logger.info("=================認證失敗==============");
return new ResultJson(false, "身份認證失敗,跳轉到登錄頁面", "");
}
}else{
return new ResultJson(true, "已認證,跳轉到主頁面", "");
}
} catch (IncorrectCredentialsException e) {
msg = "登錄密碼錯誤. Password for account " + token.getPrincipal() + " was incorrect.";
model.addAttribute("message", msg);
System.out.println(msg);
} catch (ExcessiveAttemptsException e) {
msg = "登錄失敗次數過多";
model.addAttribute("message", msg);
System.out.println(msg);
} catch (LockedAccountException e) {
msg = "帳號已被鎖定. The account for username " + token.getPrincipal() + " was locked.";
model.addAttribute("message", msg);
System.out.println(msg);
} catch (DisabledAccountException e) {
msg = "帳號已被禁用. The account for username " + token.getPrincipal() + " was disabled.";
model.addAttribute("message", msg);
System.out.println(msg);
} catch (ExpiredCredentialsException e) {
msg = "帳號已過期. the account for username " + token.getPrincipal() + " was expired.";
model.addAttribute("message", msg);
System.out.println(msg);
} catch (UnknownAccountException e) {
msg = "帳號不存在. There is no user with username of " + token.getPrincipal();
model.addAttribute("message", msg);
System.out.println(msg);
} catch (UnauthorizedException e) {
msg = "您沒有得到相應的授權!" + e.getMessage();
model.addAttribute("message", msg);
System.out.println(msg);
}
return new ResultJson(false, "身份認證失敗,跳轉到登錄頁面", "");
}
二、在realm中進行驗證
/**
* 首先執行這個登錄驗證,身份認證
* @param token
* @return
* @throws AuthenticationException
*/
@SuppressWarnings("unused")
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
System.out.println("----->doGetAuthenticationInfo-->身份認證"+22222);
//1.把AuthenticationToken轉換為UsernamePasswordToken,token中儲存着輸入的用户名和密碼 ,用户名用來確定賬號是否存在,密碼用來鹽值加密
CustomizedToken userToken = (CustomizedToken) token;
//2.獲取系統管理員賬號
String username = userToken.getUsername() ;
//3.根據系統管理員賬號獲取系統管理員信息
SystemUser user = userMapper.findUserByUsername(username) ;
System.out.println("user---------->"+user.toString());
//4.系統管理員存在則進行密碼校驗,否則,拋出異常:系統管理員不存在;
if (user!= null){
String roleName = userMapper.findRoles(username);
//將前台需要的值放到session中去,方便使用
SecurityUtils.getSubject().getSession().setAttribute("roleName",roleName);
SecurityUtils.getSubject().getSession().setAttribute("id",user.getId());
System.out.println("從數據看中獲取UserName為"+user.getUsername()+"所對應的信息。");
//1)principal:認證的實體信息,可以是username,也可以是數據庫表對應的用户的實體對象
Object principal = user.getUsername();
//2)credentials:數據庫中的密碼
Object credentials = user.getUserpassword();
//3)realmName:當前realm對象的name,調用父類的getName()方法即可
String realmName = getName();
//4)credentialsSalt鹽值
ByteSource credentialsSalt = ByteSource.Util.bytes(username);//使用賬號作為鹽值
//根據用户的情況,來構建AuthenticationInfo對象,通常使用的實現類為SimpleAuthenticationInfo
//5)與數據庫中用户名和密碼進行比對,密碼鹽值加密,第4個參數傳入realName。
SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(principal, credentials, credentialsSalt, realmName);
return info;
}else{
//6.若用户不存在,可以拋出UnknownAccountException
System.out.println("======不存在該用户=========>");
throw new UnknownAccountException("不存在該用户");//沒找到帳號
}
}
三、以上便是登錄和驗證,但是問題是,shiro如何知道我們的密碼時以什麼方式加密的,加密了多少次呢?
具體配置如下:在配置realm的bean時,設置加密類型及加密的次數,這樣shiro就知道了該如何對用户輸入的密碼進行驗證,如果正確就驗證通過,否則,驗證失敗
<!-- 註冊自定義的Realm-->
<bean id="XXXRealm" class="com.shiro.XXXRealm">
<!-- 配置密碼匹配器 -->
<property name="credentialsMatcher">
<bean class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
<!-- 加密算法為MD5 -->
<property name="hashAlgorithmName" value="MD5"></property>
<!-- 加密次數 -->
<property name="hashIterations" value="1024"></property>
</bean>
</property>
</bean>
<bean id="YYYRealm" class="com.shiro.YYYRealm">
<!-- 配置密碼匹配器 -->
<property name="credentialsMatcher">
<bean class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
<!-- 加密算法為MD5 -->
<property name="hashAlgorithmName" value="MD5"></property>
<!-- 加密次數 -->
<property name="hashIterations" value="1024"></property>
</bean>
</property>
</bean>
<bean id="cacheManager" class="org.apache.shiro.cache.MemoryConstrainedCacheManager" />
<!-- 安全管理器 -->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="cacheManager" ref="cacheManager" />
<property name="authenticator" ref="authenticator"></property>
<!-- 使用下面配置的緩存管理器 -->
<property name="sessionManager" ref="sessionManager" />
<!-- 可以配置多個Realm,其實會把realms屬性賦值給ModularRealmAuthenticator的realms屬性 -->
<property name="realms">
<list>
<ref bean="XXXRealm"/>
<ref bean="YYYRealm" />
</list>
</property>
</bean>
以上是登錄的密碼驗證;
四、那註冊加密如何實現呢?
首先一定要保證註冊時的加密方式和上面的shiro的加密方式和加密的次數一致,否則註冊成功也登陸不上去,這點一定要清楚!
/******************************添加用户******************************************/
@RequestMapping("addUser")
@ResponseBody
public ResultJson addUser(XXX xxx,HttpServletRequest request){
System.out.println("======addUser=======");
System.out.println(xxx.toString());
//密碼加密並set
user.setUserpassword(ShiroMd5Util.SysMd5(xxx));
ResultJson rj = new ResultJson();
boolean addUser_bl = userService.add(user);//將用户數據插入數據庫
if (addUser_bl) {
rj.setSuccess(addUser_bl);
rj.setMsg("註冊成功!");
}else{
rj.setSuccess(addUser_boolean);
rj.setMsg("註冊失敗!");
}
return rj;
}
public class ShiroMd5Util {
//添加user的密碼加密方法
public static String SysMd5(XXX xxx) {
String hashAlgorithmName = "MD5";//加密方式
Object crdentials =xxx.getUserpassword();//密碼原值
ByteSource salt = ByteSource.Util.bytes(xxx.getUsername());//以賬號作為鹽值
int hashIterations = 1024;//加密1024次
SimpleHash hash = new SimpleHash(hashAlgorithmName,crdentials,salt,hashIterations);
return hash.toString();
}
}
註冊時密碼加密如上即可;
五、修改密碼時如下:
/******************************更新用户******************************************/
@RequestMapping("updateUser")
@ResponseBody
public ResultJson updateUser(XXX xxx,HttpServletRequest request){
System.out.println("======updateUser=======");
if(xxx.getId()==null){
return new ResultJson(false, "修改失敗", "不存在該用户");
}//從數據哭獲取的密碼值
String dataBaseOldPassword = userService.selectSystemUserPassword(xxx.getId());
System.out.println("dataBaseOldPassword="+dataBaseOldPassword);
//從頁面傳過來的舊密碼值
String pageReturnOldPassword =ShiroMd5Util.UpdateSysMd5(xxx);//這個方法和上面的SysMd5一樣,就是換了個馬甲
System.out.println("pageReturnOldPassword="+pageReturnOldPassword);
if(!dataBaseOldPassword.equals(pageReturnOldPassword)){
return new ResultJson(false, "修改失敗", "舊密碼不正確");
}
//如果輸入的舊密碼和數據庫一致,則將用户傳進來的新密碼覆蓋舊密碼,修改密碼
user.setUserpassword(ShiroMd5Util.SysMd5(user));
ResultJson rj = new ResultJson();
//根據傳進來的xxx的值是否存在更新數據
boolean upbl = userService.updateByPrimaryKeySelective(xxx);
if(upbl){
rj.setSuccess(upbl);
rj.setMsg("修改成功");
rj.setObj("1");
}else{
rj.setSuccess(upbl);
rj.setMsg("修改失敗");
rj.setObj("0");
}
return rj;
}
相關JSp頁面代碼如下,只粘貼關鍵代碼:
<%@ page language="java" cnotallow="text/html; charset=UTF-8" pageEncoding="UTF-8"%><%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="shiro" uri="http://shiro.apache.org/tags"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<script type="text/javascript" src="<%=basePath %>js/jquery-easyui-1.5.3/jquery.min.js"></script>
<script type="text/javascript" src="<%=basePath %>js/jquery-easyui-1.5.3/jquery.easyui.min.js"></script>
<script type="text/javascript" src="<%=basePath %>js/jquery-easyui-1.5.3/locale/easyui-lang-zh_CN.js"></script>
<link rel="stylesheet" type="text/css" href="<%=basePath %>js/jquery-easyui-1.5.3/themes/default/easyui.css"></link>
<link rel="stylesheet" type="text/css" href="<%=basePath %>js/jquery-easyui-1.5.3/themes/icon.css" ></link>
<link rel="stylesheet" type="text/css" href="<%=basePath %>js/jquery-easyui-1.5.3/themes/iconexp.css" ></link>
<link rel="stylesheet" href="<%=basePath %>font/font-awesome.min.css" type="text/css"></link>
<link rel="stylesheet" href="<%=basePath %>css/home.css" type="text/css"></link>
<script type="text/javascript">
$(function(){
userForm = $('#userForm').form();
updatePasswordDialog = $('#updatePasswordDialog').show().dialog({
modal : true,
maximizable:true,
resizable:true,
width: 400,
title : '修改密碼',
buttons : [
{
text : '確定',
handler : function() {
if (userForm.find('[name=id]').val()!='') {
userForm.form('submit', {
url : '<%=basePath%>UserManager/updateUser.do',
success : function(data) {
console.log(data);
var d = $.parseJSON(data);
if (d.success) {
updatePasswordDialog.dialog('close');
$.messager.show({
msg : '修改成功!',
title : '提示'
});
alert("修改成功,請到登錄頁面重新登錄!");
//修改成功,重新登錄
logout(true);
}
}
});
}else{
$.messager.show({
msg : '修改失敗,請重新登錄嘗試修改!',
title : '提示'
});
}
}
},
{
text : '取消',
handler : function() {
updatePasswordDialog.dialog('close');
}
}
]
}).dialog('close');
});
function updatePassWord() {//打開增加部門領導的dialog的方法
updatePasswordDialog.dialog('open');
}
/*******************************************updatePassword-end****************************************************/
</script>
</head>
<body class="easyui-layout" >
<div region="north" split="false" border="false" id="north" style="height: 100px; background: url('<%= request.getContextPath()%>/image/head-bg.jpg'); ">
<div style="float:right; height: 100px; width:70%;">
...........省略無關代碼.............
<div >
<p class='icon' >
<shiro:hasRole name="super">
<a id="setIcon" style="visibility:hidden"><span onclick="settingNow()">設置</span></a>
</shiro:hasRole>
<a onclick="updatePassWord()"><span>修改密碼</span></a>|
</p>
</div>
</script>
</div>
<div style="height:100px;padding-left:22px; width: 400px; ">
<img id="loginImg" src="<%= request.getContextPath()%>/image/companyLogo.png" width="65px" height="65px" style="margin-top: 20px;float: left;"/>
<p style="margin:12px 0 0 70px; padding-top: 25px; float: left;">
<span id="newUserName" style="font-size: 14px; margin-top: 10px; color:#f00 " ><%=session.getAttribute("userName")%> 歡迎您!</span>
</p>
</div>
</div>
<div id="updatePasswordDialog" style="display: none; overflow: hidden;">
<form id="userForm" method="post">
<input type="text" readonly="true" name="id" style="display: none; overflow: hidden;" value="<%=session.getAttribute("id")%>"/>
<input type="text" readonly="true" name="username" style="display: none; overflow: hidden;" value="<%=session.getAttribute("userName")%>"/>
<table width="400" height="100" align="center" style="margin-top:20px">
<tr>
<td width="130" align="right" valign="middle">請輸入舊密碼:</td>
<td width="157" align="left" valign="middle">
<input type="password" name="olduserpassword" placeholder="輸入舊密碼">
</td>
</tr>
<tr>
<td align="right" valign="middle">請輸入新密碼:</td>
<td align="left" valign="middle">
<input type="password" name="userpassword" id="pwd1" placeholder="輸入新密碼">
</td>
</tr>
<tr>
<td align="right" valign="middle">請再次新密碼:</td>
<td align="left" valign="middle">
<input type="password" name="againpassword" id="pwd2" placeholder="確認新密碼">
</td>
</tr>
<tr>
<td align="right" valign="middle"></td>
<td align="left" valign="middle">
<span type="type" class="passwsordError" readonly="true" style="display: none; overflow: hidden;" val=""></span>
</td>
</tr>
</table>
</form>
</div>
<script>
$(function(){
$("#pwd2").blur(function(){
var pwd1=$("#pwd1").val();
var pwd2=$(this).val();
if(pwd1!=pwd2){
$(".passwsordError").text("*兩次密碼輸入不一致").css({"color":""});
$(".passwsordError").show();
}else{
$(".passwsordError").hide();
}
});
});
</script>
</body>
</html>
本文章為轉載內容,我們尊重原作者對文章享有的著作權。如有內容錯誤或侵權問題,歡迎原作者聯繫我們進行內容更正或刪除文章。