登录认证与角色

  1. 登录功能       
    1. 数据库密码修改

如果咱们数据库的密码现在没有进行加密,咱们先把它们进行加密

       (注:如果已经进行过加密就不需要再管了)

      1. 准备一个加密算法

public class MD5Util {
   // String algorithmName, Object source, Object salt, int hashIterations
    //
设置盐值
    public static final String SALT = "itsource";
    //
设置遍历次数
    public static final int HASHITERATIONS = 10;
    //
传入一个字符串,返回一个md5编码的值
    public static String createMd5Str(String str){
        SimpleHash hash =
new SimpleHash("MD5",str,SALT,HASHITERATIONS);
       
return hash.toString();
    }
}

 

      1. 通过算法修改数据库密码

@Test
public void testUpdatePwd() throws Exception{
    List<Employee> list =
employeeService.findAll();
   
for (Employee employee : list) {
        employee.setPassword(MD5Util.createMd5Str(employee.getPassword()));
       
employeeService.save(employee); //:save是添加与修改
   
}
}

      1. 添加员工时密码应该加密

EmployeeServiceImpl

@Override
public void save(Employee employee) {
   
if(employee.getId()==null){
       
//代表是添加功能(需要进入密码加密)
       
employee.setPassword(MD5Util.createMd5Str(employee.getPassword()));
    }
   
super.save(employee);
}

    1. 准备登录页面
      1. login.jsp(页面大家直接拷备即可)

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

大家必需自己找漂亮页面来用!!!!

<%--
  Created by IntelliJ IDEA.
  User: zhaoyi
  Date: 2018/10/14
  Time:
下午4:27
  To change this template use File | Settings | File Templates.
--%>
<%@
page contentType="text/html;charset=UTF-8" language="java" %>
<
html>
<
head>
    <
title>源码智销系统</title>
<%@
include file="/WEB-INF/views/head.jsp"%>
</
head>
<
body>


<
div align="center" style="margin-top: 100px;">
    <
div class="easyui-panel" title="智销系统用户登陆" style="width: 350px; height: 240px;">
        <
form id="loginForm" class="easyui-form" method="post">
            <
table align="center" style="margin-top: 15px;">
                <
tr height="20">
                    <
td>用户名:</td>
                </
tr>
                <
tr height="10">
                    <
td><input name="username" class="easyui-validatebox" required="true" value="admin" /></td>
                </
tr>
                <
tr height="20">
                    <
td>&emsp;:</td>
                </
tr>
                <
tr height="10">
                    <
td><input name="password" type="password" class="easyui-validatebox" required="true" value="0" /></td>
                </
tr>
                <
tr height="40">
                    <
td align="center"><a href="javascript:;" class="easyui-linkbutton" οnclick="submitForm();">登陆</a> <a
                           
href="javascript:;" class="easyui-linkbutton" οnclick="
resetForm();">重置</a></td>
                </
tr>
            </
table>
        </
form>
    </
div>
</
div>
</
body>
</
html>

 

      1. 修改LoginController

@Controller
public class LoginController {
    //
用于完成跳转
    @RequestMapping(value="/login",method = RequestMethod.GET)
   
public String index(){
       
return "login";
    }
    //
用于完成登录
    @RequestMapping(value="/login",method = RequestMethod.POST)
   
public String login(String username,String password){

        

      1. 修改applicationContext-shiro.xml

<!-- 5.shiro的真实过滤器(注:这个名称必需和web.xml的代表过滤器【DelegatingFilterProxy】名称一样) -->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
    <
property name="securityManager" ref="securityManager"/>
    <!--
登录的url,如果没有登录,你访问的路径会跳到这个页面 -->
   
<property name="loginUrl" value="/login"/>
    <!--
登录成功的url,如果登录成功,会跳转到这个页面 -->
   
<property name="successUrl" value="/main"/>
    <!--
没有权限时跳转到这个位置 -->
   
<property name="unauthorizedUrl" value="/s/unauthorized.jsp"/>
      <!--
这个配置我们可以直接给一个map(动态的可以从代码中获取) -->
   
<property name="filterChainDefinitionMap" ref="filterChainDefinitionMap"></property>
</
bean>

      1. 设置静态资源设置放行

如果不设置,有些浏览器引入js,css等会出问题

/**
 *
准备一个构造器类
 */
public class FilterChainDefinitionMapBuilder {

   
public Map<String,String> createFilterChainDefinitionMap(){
        Map<String, String> filterChainDefinitionMap =
new LinkedHashMap();
        //
:对于一些不登录也可以放行的设置(大家可以根据实际情况添加)
        filterChainDefinitionMap.put("/login","anon");
        filterChainDefinitionMap.put(
"*.js","anon");
        filterChainDefinitionMap.put(
"*.css","anon");
        filterChainDefinitionMap.put(
"/css/**","anon");
        filterChainDefinitionMap.put(
"/js/**","anon");
        filterChainDefinitionMap.put(
"/easyui/**","anon");
        filterChainDefinitionMap.put(
"/images/**","anon");
        //
这个值之后从数据库中查询到【用户-角色-权限-资源】
        //filterChainDefinitionMap.put("/s/permission.jsp","perms[user:*]");
        //filterChainDefinitionMap.put("/s/employee.jsp","perms[employee:*]");
        filterChainDefinitionMap.put(
"/**","authc");
       
return  filterChainDefinitionMap;
    }
}

 

完成后,咱们现在如果没有登录,就会回到相应相应的登录页面

 

 

    1. 完成登录功能
      1. EmployeeService:提供根据名称查询用户功能

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

 

      1. JpaRealm:数据库数据

 

public class JpaRealm extends AuthorizingRealm {

   
@Autowired
   
private IEmployeeService employeeService;

   
。。。

   
//AuthenticationInfo:认证; 身份验证; 证明
    //登录的时候就会调用这个方法来做验证
   
@Override
   
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
       
//身份认证(用户名)
        // 1.拿到用户名
       
UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken)token;
        String username = usernamePasswordToken.getUsername();
       
// 2.根据用户名到数据库拿到用户
       
Employee loginUser = employeeService.findByUsername(username);
        if(loginUser==null){
           
return null; //该用户名不存在
       
}
       
//从数据库中拿到密码
       
Object credentials = loginUser.getPassword();
        //加盐的数据
       
ByteSource byteSource = ByteSource.Util.bytes("itsource");
       
return new SimpleAuthenticationInfo(loginUser,credentials,byteSource,getName());
    }
}

      1. JsonResult:返回数据封装

//封装对象,确定返回值
public class JsonResult {

   
//是否操作成功
   
private boolean success = true;
   
//相应的提示信息
   
private String msg;

   
public JsonResult(){}
   
public JsonResult(boolean success, String msg) {
       
this.success = success;
       
this.msg = msg;
    }
   
。。。
}

      1. LoginController:登录功能

@RequestMapping(value="/login",method = RequestMethod.POST)
@ResponseBody
public JsonResult login(String username, String password){
    //1.
拿到访问的主体(当前登录用户)
   
Subject subject = SecurityUtils.getSubject();
    //2.
判断这个用户是否已经登录(通过验证)
   
if(!subject.isAuthenticated()){
        //3.
如果没有验证,就要完成登录
       
UsernamePasswordToken token = new UsernamePasswordToken(username,password);
       
try{
            //4.
根据toke完成登录功能
           
subject.login(token);
        }
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();
}

 

      1. login.jsp:登录功能

function submitForm() {
   
$("#loginForm").form("submit", {
       
url : "/login",
       
success : function(data) {
            data =
$.parseJSON(data);
            if (data.success) {
               
location.href = "/main";
            }
else {
               
$.messager.alert("温馨提示", data.msg, "info");
            }
        }
    });
}

function resetForm() {
   
$("#loginForm").form("clear");
}

    1. 其它功能
      1. 回车登录(理解代码即可)

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

      1. 登录过期问题

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

      1. 展示用户名与注销

main.jsp:在资源中可以找到标签配置

<body class="easyui-layout">
<
div data-options="region:'north',split:true" style="height:100px;">
    <
h1 style="margin-bottom: 10px;">源码时代智销系统</h1>
    <
div style="text-align: right; margin-right:10px;">
        <
shiro:user>
           
欢迎[<shiro:principal

 />]登录,<a href="${pageContext.request.contextPath}/logout">退出</a>
        </
shiro:user>
    </div>
</
div>
<
div data-options="region:'west',title:'菜单',split:true" style="width:230px;">
    <
ul id="menuTree"></ul>
</
div>
<
div id="dataTab" data-options="region:'center'"
    
class="easyui-tabs" style="padding:5px;background:#eee;">
    <
div title="Home">
    </
div>
</
div>
</
body>

 

  用户-角色-权限-资源

  1. 权限domain部分
    1. 为什么要做权限

为什么要做权限?对于我们系统的一些功能只有特定角色用户才能访问。要做权限判断。

 

资源/菜单

系统中所有可以访问的功能(其实还是:url的访问地址也可以说是控制器的方法

        资源的格式:

            自己实现拦截:

                   控制器的全类名:方法名

                     即:cn.itsource.crm.web.controller.EmployeeController.list

            Shiro拦截:

                 Url:/department/add

 

权限:简单理解就是给资源加锁。

针对资源,代表对某个资源的功能添加了控制,就是需要控制权限(即上锁)。

针对用户,代表用户可以使用某个被控制的功能(即钥匙,钥匙是通过角色获取的)。

 

角色:针对权限,即权限的打包,就是权限组。

用户:访问系统的人。

    1. 权限相关实体关系

 

用户----多对多---角色--多对多---权限- 多种方案---资源

 

权限和资源之间的关系分:一对一,多对一,多对多

 

      1. 权限和资源之间的一对一

一个权限只用来控制一个资源。

CREATE TABLE `t_resource` (

  `id` bigint(20) NOT NULL AUTO_INCREMENT,

  `name` varchar(255) NOT NULL,

  `url` varchar(255) NOT NULL, 如果是自己拦截换成Controller.方法名,shiro不变

  `status` int(11) NOT NULL,

  PRIMARY KEY (`id`)

) ENGINE=InnoDB DEFAULT CHARSET=utf8;

 

CREATE TABLE `t_permission` (

  `id` bigint(20) NOT NULL AUTO_INCREMENT,

  `name` varchar(40) NOT NULL,

   resourceId

  `resource` varchar(80) NOT NULL,

  PRIMARY KEY (`id`),

  KEY `id` (`id`)

) ENGINE=InnoDB DEFAULT CHARSET=utf8;

 

 

在权限表中添加资源ID外键字段。变形在权限中添加一个资源的字段,不要资源表。

 

      1. 权限与资源之间的多对多

 

一个权限控制器多个资源,一个资源属于多个权限。

列表部门权限-----列表部门资源,列表员工资源

列表员工资源---列表员工权限,列表部门权限

 

    1. 创建Domain
      1. Employee

@Entity
@Table
(name="employee")
public class Employee extends BaseDomain {

   

     //多对多:配置中间表
   
@ManyToMany(fetch = FetchType.LAZY)
   
@JoinTable(name = "employee_role",
            joinColumns =
@JoinColumn(name = "employee_id"),
            inverseJoinColumns =
@JoinColumn(name = "role_id")
    )

   @JsonIgnore //生成json是忽略这个属性(数据大多,全部拿到没有意义,还有可能造成死循环)
    private Set<Role> roles = new HashSet<>();

}

      1. Role

@Entity
@Table
(name="role")
public class Role extends BaseDomain {

   
private String name; //角色名称
    private String sn; //角色编码
    //角色对应权限
   
@ManyToMany(fetch = FetchType.LAZY)
   
@JoinTable(name = "role_permission",
            joinColumns =
@JoinColumn(name = "role_id"),
            inverseJoinColumns =
@JoinColumn(name = "permission_id")
    )
    
private List<Permission> permissions = new ArrayList<>();
     …
}

 

      1. Permission

@Entity
@Table
(name="permission")
public class Permission extends BaseDomain {
   
private String name;
   
private String url; //对应的资源
   
private String descs;
   
private String sn; //对象的权限名称
    ….

}

 

使用代码生成器生成相应的文件功能!

 

      1. 完善权限页面

<table id="permissionGrid" >
    <
thead>
    <
tr>
        <
th width="20"  field="name" >名称</th>
        <
th width="20"  field="url" >对应的资源</th>
        <
th width="20"  field="sn" >对象的权限</th>
        <
th width="20"  field="descs" >描述</th>
    </tr>
    </
thead>
</
table>

 

<div id="permissionDialog" class="easyui-dialog" data-options="closed:true,modal:true" title="功能操作" style="width:400px">
    <
div style="padding:10px 60px 20px 40px">
        <
form id="permissionForm" class="easyui-form" method="post" data-options="">
            <
input type="hidden" id="permissionId" name="id" >
            <
table cellpadding="5">
                <
tr>
                    <
td>名称:</td>
                    <
td><input class="easyui-validatebox" name="name" data-options="required:true"></input></td>
                </
tr>
                <
tr>
                    <
td>资源路径:</td>
                    <
td><input class="easyui-validatebox" type="text" name="url" data-options="required:true"></input></td>
                </
tr>
                <
tr>
                    <
td>权限:</td>
                    <
td><input class="easyui-validatebox" type="text" name="sn" data-options="required:true"></input></td>
                </
tr>
                <
tr>
                    <
td>描述:</td>
                    <
td><input class="easyui-validatebox" type="text" name="descs"></input></td>
                </
tr>
            </table>
        </
form>

       …
    </
div>

 

 

  1. 角色管理(页面功能)

 

    1. 准备角色数据显示
      1. role.jsp

<table id="roleGrid" class="easyui-datagrid" data-options="fit:true,fixed:true,fitColumns:true,toolbar:'#tb',singleSelect:true";
       url=
"/role/page"
      
iconCls="icon-save"
      
rownumbers="true" pagination="true">
    <
thead>
    <
tr>
        <
th width="20"  field="name" >名称</th>
        <
th width="20"  field="sn" >编码</th>
        <
th width="20"  field="permissions" data-options="formatter:formatperms">权限</th>
    </
tr>
    </
thead>
</
table>

      1. role.js

function formatperms(val){
   
var persStr = "" ;
   
for(var i=0;i<val.length;i++){
       
var permission = val[i];
       
persStr += permission.name;
       
if(i<val.length-1){
           
persStr+=",";
        }
    }
   
return persStr;
}

    1. 添加修改角色

<div id="roleDialog" class="easyui-dialog" data-options="closed:true,modal:true" title="功能操作" style="width:900px">
    <
div style="padding:10px 60px 20px 40px">
        <
form id="roleForm" class="easyui-form" method="post" data-options="">
            <
input type="hidden" id="roleId" name="id" >
            <
table cellpadding="5" style="width: 100%;">
                <
tr>
                    <
td>
                       
名称:<input class="easyui-validatebox" type="text" name="name" data-options="required:true"></input>
                       
编码:<input class="easyui-validatebox" type="text" name="sn" data-options="required:true"></input>
                    </
td>
                </
tr>
                <
tr>
                   <
td colspan="2">
                       <
div id="cc" class="easyui-layout" style="width: 100%;height:400px;">
                           <
div data-options="region:'west',split:true" style="width:50%;">
                               <
table id="userPermissionGrid">
                                   <thead>
                                   <
tr>
                                       <
th width="10"  field="name" >名称</th>
                                       <
th width="20"  field="url" >对应的资源</th>
                                       <
th width="20"  field="sn" >对象的权限</th>
                                   </
tr>
                                   </
thead>
                               </
table>
                           </
div>
                           <
div data-options="region:'center'" style="padding:5px;background:#eee;">
                               <
table id="allPermissionGrid">
                                   <thead>
                                   <
tr>
                                       <
th width="10"  field="name" >名称</th>
                                       <
th width="20"  field="url" >对应的资源</th>
                                       <
th width="20"  field="sn" >对象的权限</th>
                                   </
tr>
                                   </
thead>
                               </
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" οnclick="$('#roleDialog').dialog('close')">取消</a>
        </
div>
    </
div>
</
div>

 

role.js


//用户权限列表
var userPermissionGrid =$("#userPermissionGrid");
//所有权限列表
var allPermissionGrid =$("#allPermissionGrid");


var itsource={
   

    //添加数据(弹出添加的模态框)
   
add:function () {
       
//如果有data-save属性,我们把它展示出来
       
$("*[data-save]").show();
       
//启动有data-save属性的input元素的验证功能
       
$("*[data-save] input").validatebox("enableValidation");
        roleForm.
form("clear");//清除数据
        //
弹出表单窗口
       
roleDialog.dialog("center").dialog('open');
       
//当前用户权限清空
       
userPermissionGrid.datagrid("loadData",[]);
    },
   
//修改数据(弹出修改的模态框)
   
edit:function () {
       
//选中了某一条数据才删除
       
var row = roleGrid.datagrid("getSelected");
       
if(row){
           
//隐藏有data-save属性的元素
           
$("*[data-save]").hide();
           
//禁用有data-save属性的input元素的验证功能
           
$("*[data-save] input").validatebox("disableValidation");

            roleForm.
form("clear");//清除数据
           
roleDialog.dialog("center").dialog('open');
           
//form加载数据
           
roleForm.form("load",row);

           
//单独解决权限的回显问题(注意,这里要准备一个新的权限,以免删除时出问题)
           
var permissions = [];
           
$.extend(permissions,row.permissions);
            userPermissionGrid.
datagrid("loadData",permissions);

        }else{
           
$.messager.alert('提示信息','请选择一行再进行修改!','info');
        }
    },

   …

    //双击所有权限,把一个权限交给这个角色
   
addPermission:function(rowIndex, rowData){
       
//判断是否有重复的行
        //1.
拿到角色权限所有的行数据
       
var rows = userPermissionGrid.datagrid("getRows");
       
//2.遍历rows拿到每一个员工数据
       
for(var i=0;i<rows.length;i++){
           
var row = rows[i];                //3.判断如果出现相等数据的情况

           
if(row.id == rowData.id){
               
//不做任何操作(也可以给出提示)
               
$.messager.show({
                   
title:'提示',
                   
msg:'该权限已经添加!',
                   
timeout:2000,
                   
showType:'slide'
               
});
               
return;
            }
        }
       
//把数据加到相应角色权限Grid
       
userPermissionGrid.datagrid("appendRow",rowData);
    },
   
//双击后移动相应的权限
   
removePermission:function (rowIndex, rowData) {
        userPermissionGrid.
datagrid("deleteRow",rowIndex);
    }

}

//我们在这里创建两个Grid
//1.
创建当前角色的权限Grid
userPermissionGrid.datagrid({
   
fit:true,
   
fixed:true,
   
fitColumns:true,
   
//双击后移除权限
   
onDblClickRow:itsource.removePermission
})

//2.获取所有权限的Grid
allPermissionGrid.datagrid({
   
fit:true,
   
fixed:true,
   
fitColumns:true,
   
//toolbar:'#tb',
    // singleSelect:true";
   
url:"/permission/page",
   
rownumbers:"true" ,
   
pagination:"true",
   
//双击后添加权限
   
onDblClickRow:itsource.addPermission
})

    1. 保存数据

var itsource={
    //
保存数据
   
save:function () {
       
var url  = "/role/save";
       
var id = $("#roleId").val();
       
if(id){
           
url = "/role/update?cmd=update";
        }
       
roleForm.form('submit', {
           
url:url,
            //
这里我们加上params,可以通过这个参数修改咱们的提交数据
           
onSubmit: function(param){
                //
得到所有明细
               
var rows = userPermissionGrid.datagrid("getRows");
                //
准备传参数据(权限多条数据,是个数组)
                //param.permissions = [];
               
for(var i=0;i<rows.length;i++){
                    //
设置相应的数据值
                   
param["permissions["+i+"].id"] =rows[i].id;
                }


                //做验证
               
return roleForm.form("validate");
            },
           
success:function(data){
                
var result = JSON.parse(data);//转成相应的json数据
               
if(result.success) {
                   
roleGrid.datagrid('reload');
                   
roleDialog.dialog('close');
                }
else{
                   
$.messager.alert('提示信息','操作失败!,原因:'+result.msg,"error");
                }
            }
        })
    }
   }

 

/**
 *
特性:在执行相应方法之前都会先执行这个方法
 */

@ModelAttribute("editRole")
public Role beforeEdit(Long id, String cmd){
   
//id的时候-> 修改功能
   
if(id!=null && "update".equals(cmd)) {
        Role role =
roleService.findOne(id);
       
//把这个要修改的关联对象设置为null,可以解决n-to-n的问题
        
role.getPermissions().clear();
        return role;
    }
   
return null;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值