zoukankan      html  css  js  c++  java
  • Shiro自定义realm实现密码验证及登录、密码加密注册、修改密码的验证

    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, 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; 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; 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>
  • 相关阅读:
    web.xml配置详解
    javascript实现的网页打印
    C#实现新建文件并写入内容
    nodeJs学习过程之认识nodejs
    windows下nodejs与coffeeScript环境搭建
    javascript/css压缩工具---yuicompressor使用方法
    verilog描述表决器的两种方式简易分析
    verilog阻塞与非阻塞的初步理解(二)
    verilog阻塞与非阻塞的初步理解(一)
    FIFO学习心得
  • 原文地址:https://www.cnblogs.com/handsome1013/p/10928412.html
Copyright © 2011-2022 走看看