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" contentType="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")%>&nbsp;&nbsp;歡迎您!</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>

end!

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM