智销功能_登录与角色

一.登录

1.1 准备登录页面(随便找一个即可)

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

js代码部分

 //登录功能
function submitForm(){
    $('#loginForm').form('submit', {
        url:"/login",
        onSubmit: function(){
            return $(this).form('validate');
        },
        success:function(data){
            var result = JSON.parse(data);
            if(result.success){
                //成功后跳转到主页面
                window.location.href = "/main";
            }else{
                $.messager.alert("提示",result.msg,"error");
            }
        }
    });
}

1.2 LoginController功能

1.2.1 两个login方法

一个用于跳转(/login,get),一个用于登录(/login,post)

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

/**
 * 是一个Ajax的登录请求,它会返回{success:true/false,msg:xxx}
 * @return
 */
@RequestMapping(value="/login",method = RequestMethod.POST)
@ResponseBody
public JsonResult login(String username, String password){
  ...
}

1.2.2完成登录的功能

@RequestMapping(value="/login",method = RequestMethod.POST)
@ResponseBody
public JsonResult login(String username, String password){
    //1.拿到当前用户
    Subject currentUser = SecurityUtils.getSubject();
    //2.如果没有登录,进行登录
    if(!currentUser.isAuthenticated()){
        //3.准备令牌
        UsernamePasswordToken token = new UsernamePasswordToken(username, password);
        //4.实现登录
        try {
            currentUser.login(token);
        } catch (UnknownAccountException e) {
            e.printStackTrace();
            return new JsonResult(false, "用户名不存在!");
        } catch (IncorrectCredentialsException e) {
            e.printStackTrace();
            return new JsonResult(false, "账号或密码错误!");
        } catch (AuthenticationException e) {
            e.printStackTrace();
//                System.out.println("就是登录不了(请联系程序员...)");
            return new JsonResult(false, "网络出错(联系管理员)!");
        }
    }
    //登录成功成功令牌
    return new JsonResult();
}

1.3 登录细节

1.3.1 数据库的密码设置

要有一套自己的密码规则(md5,10次,盐值:itsource)

a.MD5Util

public class MD5Util {

    public static final String SALT = "itsource";
    public static final Integer HASHITERATIONS = 10;

    //密码加密
    public static String changePwd(String password){
        SimpleHash hash = new SimpleHash("MD5",password,SALT,HASHITERATIONS);
        return  hash.toHex();
    }
}

b.添加用户密码加密

controller或者service中都可以进行[我们选择service]

@Override
public void save(Employee employee) {
    if(employee.getId()==null){
        //添加功能就进行密码修改
        employee.setPassword(MD5Util.changePwd(employee.getPassword()));
    }
    employeeRepository.save(employee);
}

c.加密的判断必需和规则一致

applicationContext-shiro.xml(编码方式与次数)

<!-- 被引用的realm(一定会写一个自定义realm) -->
<bean id="jpaRealm" class="cn.itsource.aisell.shiro.JpaRealm">
    <!-- 为这个realm设置相应的匹配器 -->
    <property name="credentialsMatcher">
        <bean class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
            <!-- 设置加密方式 -->
            <property name="hashAlgorithmName" value="md5"/>
            <!-- 设置加密次数 -->
            <property name="hashIterations" value="10" />
        </bean>
    </property>
</bean>

JpaRealm(加盐一致)

//身份认证
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
    //1.拿用户名与密码
    UsernamePasswordToken token = (UsernamePasswordToken)authenticationToken;
    String username = token.getUsername();
    //2.根据用户名拿到相应的对象
    Employee loginUser = employeeService.findByUsername(username);
    if(loginUser==null){
        return null; //如果用户用空代表用户名不存在
    }
    String password = loginUser.getPassword();
    //返回认证信息
    //准备盐值
    //传的第一个值就是主体(username名称做的主体)
    ByteSource salt = ByteSource.Util.bytes(MD5Util.SALT);
    SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(username,password,salt,getName());
    return authenticationInfo;
}

1.3.2 其它细节

a.静态资源放行

有些地方没有登录也可以直接使用(FilterChainDefinitionMapFactory)

public Map<String,String> createFilterChainDefinitionMap(){
        //注:LinkedHashMap是有序的
        Map<String,String> filterChainDefinitionMap = new LinkedHashMap<>();

        filterChainDefinitionMap.put("/s/login.jsp", "anon");
        filterChainDefinitionMap.put("/login", "anon");
        //把所有静态资源进行放行
        filterChainDefinitionMap.put("*.js", "anon");
        filterChainDefinitionMap.put("*.css", "anon");
        filterChainDefinitionMap.put("/easyui/**", "anon");
        filterChainDefinitionMap.put("/images/**", "anon");
        filterChainDefinitionMap.put("/js/**", "anon");

        filterChainDefinitionMap.put("/s/permission.jsp", "perms[user:index]");
        filterChainDefinitionMap.put("/**", "authc");

        return filterChainDefinitionMap;
    }

b.登录过期

login.jsp

// 检查自己是否是顶级页面
if (top != window) {// 如果不是顶级
    //把子页面的地址,赋值给顶级页面显示
    window.top.location.href = window.location.href;
}

c.回车登录

login.jsp

$(document.documentElement).on("keyup", function(event) {
    //console.debug(event.keyCode);
    var keyCode = event.keyCode;
    console.debug(keyCode);
    if (keyCode === 13) { // 捕获回车
        submitForm(); // 提交表单
    }
});

d.展示用户名与注销

main.jsp

<%@ taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>
...
 <div style="text-align: right;margin-right: 20px;">
    欢迎您,亲爱的用户:<shiro:principal />
    <a href="/logout">注销</a>
</div>

LoginController

@RequestMapping("/logout")
public String logout(){
    Subject currentUser = SecurityUtils.getSubject();
    currentUser.logout();
    return "redirect:/login";
}

二.角色管理

先使用代码生成器生成Role,Permission 设置多对多的关系

//Employee
@ManyToMany
@JoinTable(name = "employee_role",
        joinColumns = @JoinColumn(name="employee_id"),
        inverseJoinColumns = @JoinColumn(name="role_id"))
private Set<Role> roles = new HashSet<>();
//Role
@ManyToMany
@JoinTable(name="role_permission",
        joinColumns = @JoinColumn(name="role_id"),
        inverseJoinColumns = @JoinColumn(name="permission_id"))
private List<Permission> permissions = new ArrayList<>();

2.1 角色中(权限的展示)

role.jsp

<table id="roleGrid" class="easyui-datagrid" fit="true"
    ...
    ">
    <thead>
    <tr>
     ...
        <th data-options="field:'permissions',width:100,formatter:formatPerms">权限</th>
    </tr>
    </thead>
</table>

role.js

//返回权限展示的方法
//v:当前数据  r:当前行数据 i:行索引
function formatPerms(v,r,i){
    var permsName = "";
    for(let o of v){
        permsName += o.name +" ";
    }
    return permsName;
}

2.1 添加权限

2.1.1 form弹出布局

左(当前权限)右(所有权限)都有一个grid

<!-- 一个弹出框,里面要装一个form表单 -->
<div id="editDlg" class="easyui-dialog" title="功能操作"
     data-options="iconCls:'icon-save',closed:true,modal:true"
     style="padding:10px;width: 850px;">
    <form id="editForm" method="post">
        <!-- 修改的话,这个id是必需的 -->
        <input id="roleId" name="id" type="hidden"/>
        <table cellpadding="5">
            <tr>
                <td>
                    名称:<input class="easyui-validatebox" type="" name="name"
                              data-options="required:true"></input>
                    编码:<input class="easyui-validatebox" type="text" name="sn"
                              data-options="required:true"></input>
                </td>
            </tr>
        </table>
        <div class="easyui-layout" style="width:100%;height:400px;">
            <div data-options="region:'west'" style="width:50%;">
                <table id="rolePermissionGrid">
                    <thead>
                        <tr>
                            <th data-options="field:'name',width:100">名称</th>
                            <th data-options="field:'sn',width:100">编码</th>
                            <th data-options="field:'url',width:100">资源路径</th>
                        </tr>
                    </thead>
                </table>
            </div>
            <div data-options="region:'center'">
                <table id="allPermissionGrid">
                    <thead>
                    <tr>
                        <th data-options="field:'name',width:100">名称</th>
                        <th data-options="field:'sn',width:100">编码</th>
                        <th data-options="field:'url',width:100">资源路径</th>
                    </tr>
                    </thead>
                </table>
            </div>
        </div>
    </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" onclick="$('#editDlg').dialog('close')">关闭</a>
    </div>
</div>

2.1.2 为角色添加/删除权限


...
var rolePermissionGrid = $("#rolePermissionGrid");
var allPermissionGrid = $("#allPermissionGrid");
...
 itsource = {
        add(){
         ...
            //清空grid中的数据
            //loadData:加载本地数据,旧的行将被移除
            rolePermissionGrid.datagrid("loadData",[]);
         ...
        },
        edit(){
           ...
            if(row){
               ...
                //拷备对应的权限数组
                var copyPerms = [...row.permissions];
                //解决Grid加显问题
                rolePermissionGrid.datagrid("loadData",copyPerms);
            }else {
              ...
        },
        //通过javascript进行保存
        save(){
           ...
            editForm.form('submit', {
                //form提交的路径
                url:url,
                //提交之前你要做什么事件
                onSubmit: function(param){
                    //添加一些提交的额外参数
                    //1.拿到grid中所有的值
                    var allRows = rolePermissionGrid.datagrid("getRows");
                    //2.循环把值放进去
                    for(var i=0;i<allRows.length;i++){
                        var row = allRows[i];
                        param[`permissions[${i}].id`] = row.id;
                    }
                    return $(this).form('validate');
                },
               ...
            });
        },
       ...
        //添加一个权限
        addPerms(index, row){
            //先拿到角色的所有权限
            var allRows = rolePermissionGrid.datagrid("getRows");
            //遍历进行比较
            for(let o of allRows){
                //如果两个权限相等,就什么都不做了
                if(o.id == row.id){
                    $.messager.show({
                        title:'注意事项',
                        msg:'这个权限已经存在,无需再进行添加!',
                        timeout:2000,
                        showType:'slide'
                    });
                    return;
                }
            }
            rolePermissionGrid.datagrid("appendRow",row);
        },
        //删除对应权限
        delPerms(index,row){
            rolePermissionGrid.datagrid("deleteRow",index);
        }
    };

    //创建当前角色对应的权限(grid控件)
    rolePermissionGrid.datagrid({
        fit:true,
        fitColumns:true,
        singleSelect:true,
        border:false,
        onDblClickRow:itsource.delPerms
    })

    //创建拿到所有的权限的grid控件
    allPermissionGrid.datagrid({
        fit:true,
        url:'/permission/page',
        fitColumns:true,
        singleSelect:true,
        pagination:true,
        border:false,
        onDblClickRow:itsource.addPerms
    })

2.1.3 只增不减的问题

修改的时候只能添加不能减少

@ModelAttribute("editRole")
public Role beforeEdit(Long id,String cmd){
    //修改的时候才查询(只要有id会就进行一次查询,这是不对的)
    if(id!=null && "update".equals(cmd)) {
        Role role = roleService.findOne(id);
        //把要传过来的关联对象都清空,就可以解决n-to-n的问题
        role.getPermissions().clear();
        return role;
    }
    return null;
}
posted @ 2019-03-29 18:06  Acrossthesky  阅读(234)  评论(0编辑  收藏  举报