易用宝项目记录day6-login和权限管理

易用宝项目记录day6-login和权限管理

1.登录界面

位置:webapp/WEB-INF/views/login.jsp

主要的是js使用easyui的ajax发送post请求

<%--
  User: xj
  Date: 2019/7/10
  Time: 16:26
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html lang="zh-cn">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"/>
    <meta name="renderer" content="webkit">
    <title>登录</title>
    <%@ include file="/WEB-INF/views/head.jsp" %>

    <link rel="stylesheet" href="/css/base.css">
    <link rel="stylesheet" href="/css/style.css">
    <script type="text/javascript">

        //判断当前页面是否是顶层页面
        if (top != window) {
            //window.top.location.href = "/login";
            window.top.location.href = window.location.href;
        }
        //回车登录
        $(document.documentElement).on("keyup", function (event) {
            console.debug(event);
            var keyCode = event.keyCode;
            if (keyCode === 13) { // 捕获回车
                submitForm(); // 提交表单
            }
        });

        //提交form表单
        function submitForm() {
            $('#loginForm').form('submit', {
                url: "/login",
                onSubmit: function () {
                    return $(this).form('validate');
                },
                //注意:现在这个data是一个字符串:{success:true,msg:""}
                success: function (data) {
                    var result = JSON.parse(data);
                    if (result.success) {
                        //如果登录成功,跳转到主页面
                        window.location.href = "/main";
                    } else {
                        //如果登录失败,给出错误提示
                        $("#msg").text(result.msg);
                        setTimeout(function () {
                            $("#msg").hide().text("");
                        }, 2000);
                        $("#msg").show();

                        //$.messager.alert('错误', result.msg);
                    }
                }
            });
        }
    </script>

</head>
<body>

<div class="bg"></div>
<div class="container">
    <div class="line bouncein">
        <div class="xs6 xm4 xs3-move xm4-move">
            <div style="height:150px;"></div>
            <div class="media media-y margin-big-bottom">
            </div>
            <form id="loginForm" action="/login" method="post" class="easyui-form">
                <div class="panel loginbox">
                    <div class="text-center margin-big padding-big-top">
                        <h1>欢迎来到易用宝</h1>
                    </div>
                    <div class="panel-body" style="padding:30px; padding-bottom:10px; padding-top:10px;">
                        <div class="form-group">
                            <div class="field field-icon-right">
                                <input type="text" class="input input-big" name="username" id="username"
                                       placeholder="登录账号"/>
                                <span class="icon icon-user margin-small"></span>
                            </div>
                        </div>
                        <div class="form-group">
                            <div class="field field-icon-right">
                                <input type="password" class="input input-big" name="password" id="password"
                                       placeholder="登录密码"/>
                                <span class="icon icon-key margin-small"></span>
                            </div>
                        </div>
                        <div class="form-group">
                            <div class="field">
                                <input type="text" class="input input-big" name="captcha" placeholder="填写右侧的验证码"/>
                                <img src="/images/captcha"
                                     alt="" width="100" height="32" class="passcode" style="height:43px;cursor:pointer;"
                                     onClick="this.src=this.src+'?'">
                            </div>
                        </div>
                    </div>

                    <div class="form-group">
                        <div class="field field-icon-right">
                            <h3 id="msg" style="text-align: center;color: red"></h3>
                        </div>
                    </div>

                    <div style="padding:30px;">
                        <input type="button" id="button" class="button button-block bg-main text-big input-big"
                               onclick="submitForm();" value="登录">
                    </div>
                </div>
            </form>
        </div>
    </div>
</div>

</body>
</html>

2.LoginController功能

准备两个/login,一个get用于跳转页面,一个post用于登录

package cn.xiaji.web.controller;
//encoding: utf-8

import cn.xiaji.common.JsonResult;
import com.wf.captcha.Captcha;
import com.wf.captcha.SpecCaptcha;
import com.wf.captcha.utils.CaptchaUtil;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import sun.security.util.Password;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.*;
import java.util.Random;

/**
 * @author: xj
 * @contact: xiaruji520@gmail.com
 * @file: LoginController.java
 */
/*

 */
@Controller
public class LoginController {

    private Font getFont() {
        Random random = new Random();
        Font font[] = new Font[6];
        font[0] = new Font("Ravie", Font.PLAIN, 32);
        font[1] = new Font("Antique Olive Compact", Font.PLAIN, 32);
        font[2] = new Font("Forte", Font.PLAIN, 32);
        font[3] = new Font("Wide Latin", Font.PLAIN, 32);
        font[4] = new Font("Gill Sans Ultra Bold", Font.PLAIN, 32);
        font[5] = new Font("Verdana", Font.PLAIN, 32);
        return font[random.nextInt(6)];
    }

    //验证码
    @RequestMapping("/images/captcha")
    public void captcha(HttpServletRequest request, HttpServletResponse response) throws Exception {
        /*
        https://github.com/whvcse/EasyCaptcha
        */
        // 设置请求头为输出图片类型
        CaptchaUtil.setHeader(response);

        // 三个参数分别为宽、高、位数
        SpecCaptcha specCaptcha = new SpecCaptcha(130, 48, 5);

        // 设置字体
        specCaptcha.setFont(getFont());

        // 设置类型,纯数字、纯字母、字母数字混合
        specCaptcha.setCharType(Captcha.TYPE_DEFAULT);

        // 验证码存入session
        request.getSession().setAttribute("captcha", specCaptcha.text().toLowerCase());

        // 生成的验证码
        String code = specCaptcha.text();
        System.out.println(code);

        // 输出图片流
        specCaptcha.out(response.getOutputStream());

    }

    /*@PostMapping("/login")
    public JsonResult login(String username, String password, String code){
        // 获取session中的验证码
        String sessionCode = request.getSession().getAttribute("captcha");
        // 判断验证码
        if (code==null || !sessionCode.equals(code.trim().toLowerCase())) {
            return JsonResult.error("验证码不正确");
        }
    }*/

    @RequestMapping(value = "/login", method = RequestMethod.GET)
    public String index() {
        return "login";
    }

    @RequestMapping(value = "/login", method = RequestMethod.POST)
    @ResponseBody
    public JsonResult login(HttpServletRequest request, String username, String password, String captcha) {
        // 获取session中的验证码
        String code = (String) request.getSession().getAttribute("captcha");
        //判断验证码是否正确
        if (code.equals(captcha.toLowerCase())) {
            System.out.println("验证码成功!" + username + "-----" + password);
            //1.拿到当前用户
            Subject subject = SecurityUtils.getSubject();
            //2.如果没有登录就让它登录
            if (!subject.isAuthenticated()) {
                UsernamePasswordToken token = new UsernamePasswordToken(username, password);
                try {
                    subject.login(token);
                    return new JsonResult();
                } catch (UnknownAccountException e) {
                    System.out.println("用户名或者密码错误!");
                    e.printStackTrace();
                    return new JsonResult(false, "用户名或者密码错误!");
                } catch (IncorrectCredentialsException e) {
                    System.out.println("用户名或者密码错误!");
                    e.printStackTrace();
                    return new JsonResult(false, "用户名或者密码错误!");
                } catch (AuthenticationException e) {
                    System.out.println("未知错误!");
                    e.printStackTrace();
                    return new JsonResult(false, "未知错误!");
                }
            }
            return new JsonResult(false, "用户名或者密码错误!");
        } else {
            return new JsonResult(false, "验证码错误!");
        }
    }

    //登出:注销功能
    @RequestMapping("/logout")
    public String logout(){
        //拿到主体完成登出
        Subject subject = SecurityUtils.getSubject();
        subject.logout();
        //跳回到登录页面
        return "redirect:/login";
    }

}

3.密码安全问题(MD5+循环加盐)

准备一个util

package cn.xiaji.common;
//encoding: utf-8

import org.apache.shiro.crypto.hash.SimpleHash;

/**
 * @author: xj
 * @contact: xiaruji520@gmail.com
 * @file: MD5Utils.java
 */
/*

 */
public class MD5Utils {
    //加盐
    public static final String salt = "xxxx";//xxxx代表你的盐值
    //加密次数
    public static final int HASHITERATIONS = 1000;//加密循环次数

    public static String createMD5Pwd(String str) {
        SimpleHash hash = new SimpleHash("MD5", str, salt, HASHITERATIONS);
        return hash.toHex();
    }
}

在EmployeeServiceImpl 添加用户密码

package cn.xiaji.service.Impl;
//encoding: utf-8

import cn.xiaji.common.MD5Utils;
import cn.xiaji.domain.Employee;
import cn.xiaji.repository.EmployeeRepository;
import cn.xiaji.service.IEmployeeService;
import com.hazelcast.util.MD5Util;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * @author: xj
 * @contact: xiaruji520@gmail.com
 * @file: EmployeeServiceImpl.java
 */
/*

 */
@Service
public class EmployeeServiceImpl extends BaseServiceImpl<Employee, Long> implements IEmployeeService {
    @Autowired
    private EmployeeRepository employeeRepository;

    //验证用户名是否存在
    @Override
    public Boolean checkUsername(String username) {
        return !(employeeRepository.getCountByUsername(username) > 0);
    }

    @Override
    public Employee findByUsername(String username) {
        return  employeeRepository.findByUsername(username);
    }

    //添加或更新 密码加密
    @Override
    @Transactional
    public void save(Employee employee) {
        if (employee.getId() == null) {
            employee.setPassword(MD5Utils.createMD5Pwd(employee.getPassword()));
        }
        super.save(employee);
    }
}

applicationContext-shiro.xml也要注意(编码方式与次数)

 <!-- 等会需要改成自己的Realm -->
    <bean id="jdbcRealm" class="cn.xiaji.web.shiro.AISellRealm">
        <!--密码的匹配器-->
        <property name="credentialsMatcher">
            <bean class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
                <property name="hashAlgorithmName" value="MD5"/>
                <property name="hashIterations" value="1000"/>
            </bean>
        </property>
    </bean>

FilterChainDefinitionMapFactory静态资源放行

package cn.xiaji.web.shiro;
//encoding: utf-8

import java.util.LinkedHashMap;
import java.util.Map;

/**
 * @author: xj
 * @contact: xiaruji520@gmail.com
 * @file: FilterChainDefinitionMapFactory.java
 */
/*

 */
public class FilterChainDefinitionMapFactory {
    public Map<String, String> builderFilterChainDefinitionMap() {
        Map<String, String> maps = new LinkedHashMap<>();
        //maps中加数据
        //设置放行
        maps.put("/s/*", "anon");
        maps.put("/login", "anon");
        maps.put("/easyui/**", "anon");
        maps.put("/js/**", "anon");
        maps.put("/json/**", "anon");
        maps.put("/css/**", "anon");
        maps.put("*.js", "anon");
        maps.put("*.css", "anon");
        maps.put("/images/**", "anon");
        //设置权限拦截
        maps.put("/employee/index", "perms[employee:index]");
        maps.put("/dept/index", "perms[dept:index]");
        //设置拦截所有
        maps.put("/**", "authc");
        return maps;
    }
}

4.权限管理-角色管理

  1. 先在domain层建立好多对多关系

  2. role.jsp

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
        <title>易用宝,Role管理</title>
        <%@include file="/WEB-INF/views/head.jsp" %>
        <script src="/js/model/role.js"></script>
    </head>
    <body>
    
    <%--pagination:分页--%>
    <table id="roleGrid" class="easyui-datagrid"
           data-options="url:'/role/page',
           fitColumns:true,
           singleSelect:false,
           pagination:true,
           <%--onDblClickCell:onDblClickCell,--%>
           toolbar:'#gridTools',
           onRowContextMenu:showMenu">
        <thead>
        <tr>
            <th data-options="field:'id',width:100">id</th>
            <th data-options="field:'name',width:100">名称</th>
            <th data-options="field:'sn',width:100">编码</th>
            <th data-options="field:'permissions',width:100,formatter:permsFormat">权限</th>
        </tr>
        </thead>
    </table>
    
    <%--右键支持增删改--%>
    <div id="gridMenu" class="easyui-menu" style="width:120px;">
        <div data-options="iconCls:'icon-add'" data-method="add">添加</div>
        <div data-options="iconCls:'icon-edit'" data-method="update">修改</div>
        <div data-options="iconCls:'icon-remove'" data-method="del">删除</div>
        <div data-options="iconCls:'icon-remove'" data-method="delMore">批量删除</div>
    </div>
    
    <%--grid顶部工具栏--%>
    <div id="gridTools" style="padding:5px;height:auto">
        <%--功能条--%>
        <div style="margin-bottom:5px">
            <a href="#" data-method="add" class="easyui-linkbutton" iconCls="icon-add" plain="true">添加</a>
            <a href="#" data-method="update" class="easyui-linkbutton" iconCls="icon-edit" plain="true">修改</a>
            <a href="#" data-method="del" class="easyui-linkbutton" iconCls="icon-remove" plain="true">删除</a>
            <a href="#" data-method="delMore" class="easyui-linkbutton" iconCls="icon-remove" plain="true">批量删除</a>
        </div>
        <%--查询条--%>
        <form id="searchForm">
            名称:<input name="name" class="easyui-textbox" style="width:80px">
            <a href="#" data-method="search" class="easyui-linkbutton" iconCls="icon-search">查询</a>
        </form>
    </div>
    
    <%--添加与修改的表单对话框--%>
    <div id="editDialog" class="easyui-dialog" title="功能编辑" style="width:950px;"
         data-options="iconCls:'icon-save',resizable:true,modal:true,closed:true">
        <form id="editForm" method="post">
            <input id="roleId" type="hidden" name="id"/>
            <table cellpadding="5" style="width: 100%">
                <tr>
                    <td>
                        名称:
                        <input class="easyui-validatebox" type="text" name="name"
                               data-options="required:true"/>
                       &emsp; &emsp;
                        编码:
                        <input class="easyui-validatebox" type="text" name="sn"
                               data-options="required:true"/>
                    </td>
                </tr>
                <tr>
                    <td>
                        <div id="cc" class="easyui-layout" style="width:99%;height:400px;">
                            <div data-options="region:'west'" style="width:440px;">
                                <table id="userPermissionGrid"></table>
                            </div>
                            <div data-options="region:'center'">
                                <table id="allPermissionGrid"></table>
                            </div>
                        </div>
                    </td>
                </tr>
            </table>
        </form>
        <div style="text-align:center;padding:5px">
            <a href="javascript:void(0)" class="easyui-linkbutton" data-method="save">提交</a>
            <a href="javascript:void(0)" class="easyui-linkbutton" data-method="closeDialog">关闭</a>
        </div>
    </div>
    
    
    </body>
    </html>
    
  3. role.js

    //右键支持增删改
    function showMenu(e, rowIndex, rowData) {
        //选中这个行
        $("#roleGrid").datagrid("selectRow", rowIndex);
        //第0个位置的面板不支持相应功能
        e.preventDefault();
        $('#gridMenu').menu('show', {
            left: e.pageX,
            top: e.pageY
        });
    }
    
    //对权限进行相应的格式化
    function permsFormat(val) {
        var permsStr = "";
        for (let o of val) {
            permsStr += o.name + " ";
        }
        return permsStr;
    }
    
    $(function () {
        //获取常用组件(分页/查询条)
        var roleGrid = $("#roleGrid");
        var searchForm = $("#searchForm");
        var editDialog = $("#editDialog");
        var editForm = $("#editForm");
    
        //绑定事件
        $("*[data-method]").on("click", function () {
            var method = $(this).data("method");
            //动态调用
            window.xiaji[method]();
        });
    
        xiaji = {
            //查询
            search() {
                //serializeObject:可以拿到form中的所有数据,封装成json对象
                var params = searchForm.serializeObject();
                roleGrid.datagrid("load", params);
            },
            //关闭窗口
            closeDialog() {
                editDialog.dialog("close");
            },
            //添加
            add() {
                //让密码框显示
                $("*[data-edit]").show();
                $("*[data-edit] input").validatebox("enable");
                //修改弹出框Title
                editDialog.dialog('setTitle', "添加");
                //清空form中的数据
                editForm.form("clear");
                //清空左边grid的数据 loadData:加载本地数据,旧的行将被移除
                userPermissionGrid.datagrid("loadData",[]);
                //打开弹出框(居中)
                editDialog.dialog("center").dialog("open");
            },
            //保存
            save() {
                var url = "/role/save";
                //获到id的值
                var roleId = $("#roleId").val();
                if (roleId) {
                    url = "/role/update?cmd=_upd_";
                }
                //easyui的form
                editForm.form('submit', {
                    //提交路径
                    url: url,
                    //提交前的操作 param这个参数加的属性都会向后台提示
                    onSubmit: function (param) {
                        //拿到role(左边的grid)中的所有权限
                        var rows = userPermissionGrid.datagrid("getRows");
                        //遍历它,拼接出相应的结构
                        for(var i=0;i<rows.length;i++){
                            var row = rows[i];
                            param[`permissions[${i}].id`] = row.id;
                        }
                        // 做一些检查
                        return $(this).form('validate');
                    },
                    //data : {success:true/false,msg:xxx}
                    success: function (data) {
                        var result = JSON.parse(data);
                        if (result.success) {
                            roleGrid.datagrid("reload");
                        } else {
                            $.messager.alert('错误', `失败了,失败原因::${result.msg}`, "error");
                        }
                        //关闭弹出框
                        xiaji.closeDialog();
                    }
                });
            },
            //修改
            update() {
                //获取到选中的那一行数据
                var row = roleGrid.datagrid("getSelected");
                //如果没有选中,给出提示后面的代码就不再执行
                if (!row) {
                    $.messager.alert('警告', '请选中再修改!', 'warning');
                    return;
                }
                //清空form中的数据
                editForm.form("clear");
                //让密码框失效且隐藏起来
                $("*[data-edit]").hide();
                $("*[data-edit] input").validatebox("disable");
                //修改弹出框Title
                editDialog.dialog('setTitle', "修改");
                //把结果进行回显
                editForm.form("load", row);
                //打开弹出框(居中)
                editDialog.dialog("center").dialog("open");
                //回显左边grid的数据
                //获取当前选中的行的所有权限
                //必需要拷备一个数组 不然会直接修改原数据
                var permissions = [...row.permissions];
                userPermissionGrid.datagrid("loadData",permissions);
            },
            //删除
            del() {
                //获取选中数据
                var row = roleGrid.datagrid('getSelected');
                //如果没有选中给提示 选中就是否确定删除
                if (!row) {
                    $.messager.alert('警告', '请选中再删除!', 'warning');
                    return;
                } else {
                    $.messager.confirm('确认', '您确认想要删除记录吗?', function (r) {
                        if (r) {
                            //选是 确定删除
                            $.get("/role/delete", {id: row.id}, function (result) {
                                if (result.success) {
                                    roleGrid.datagrid("reload");
                                } else {
                                    $.messager.alert('错误', `失败了,失败原因:${result.msg}`, "error");
                                }
    
                            })
                        }
                    });
                }
            },
            //批量删除
            delMore() {
                //获取选中数据
                var rows = roleGrid.datagrid('getSelections');
                //如果没有选中给提示 选中就是否确定删除
                if (rows.length == 0) {
                    $.messager.alert('警告', '请选中再删除!', 'warning');
                    return;
                } else {
                    $.messager.confirm('确认', '您确认想要删除记录吗?', function (r) {
                        if (r) {
                            //定义变量值
                            for (var i = 0; i < rows.length; i++) {
                                //选是 确定删除
                                $.get("/role/delete", {id: rows[i].id}, function (result) {
                                    if (result.success) {
                                        roleGrid.datagrid("reload");
                                    } else {
                                        $.messager.alert('错误', `失败了,失败原因:${result.msg}`, "error");
                                    }
    
                                })
                            }
                        }
                    });
                }
            },
            //添加权限
            addPermission(index, row) {// index:点的行  row:这行的数据
                //获取左边grid的所有数据
                var rows = userPermissionGrid.datagrid("getRows");
                //循环所有的行,如果重复传,就不执行后面代码
                for (var o of rows) {
                    if (o.id == row.id) {
                        $.messager.show({
                            title: '提示',
                            msg: '已添加,请勿重复操作!',
                            timeout: 2000,
                            showType: 'slide',
                            style: {
                                right: '',
                                top: document.body.scrollTop + document.documentElement.scrollTop,
                                bottom: ''
                            }
                        });
                        return;
                    }
                }
                userPermissionGrid.datagrid("appendRow", row);
            },
            //删除权限
            removePermission(index, row) {
                userPermissionGrid.datagrid("deleteRow", index);
            }
        };
    
        //单独获取两个rid
        var userPermissionGrid = $('#userPermissionGrid');
        var allPermissionGrid = $('#allPermissionGrid');
    
        //创建当前角色对应的权限(左)grid
        userPermissionGrid.datagrid({
            fit: true,
            fitColumns: true,
            singleSelect: true,
            columns: [[
                {field: 'name', title: '名称', width: 100},
                {field: 'sn', title: '权限', width: 100},
                {field: 'url', title: '资源', width: 100}
            ]],
            onDblClickRow: xiaji.removePermission
        });
    
        //创建当前角色对应的权限(右)grid
        allPermissionGrid.datagrid({
            fit: true,
            url: '/permission/page',
            fitColumns: true,
            singleSelect: true,
            pagination: true,
            columns: [[
                {field: 'name', title: '名称', width: 100},
                {field: 'sn', title: '权限', width: 100},
                {field: 'url', title: '资源', width: 100}
            ]],
            onDblClickRow: xiaji.addPermission
        });
    
        //按键扩展支持
        $(document).bind('keydown', 'del', xiaji.del);
        $(document).bind('keydown', 'Shift+1', xiaji.add);
        $(document).bind('keydown', 'Shift+2', xiaji.update);
        $(document).bind('keydown', 'Shift+3', xiaji.delMore);
    
    });
    

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值