博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
后台权限管理项目总结
阅读量:2348 次
发布时间:2019-05-10

本文共 11947 字,大约阅读时间需要 39 分钟。

        最近做了一个后台的权限管理项目,没有用到springSecurity,也没有用到shiro,纯粹是用原生态的写法做的,有点粗糙,但是思想没变,这里记录一下自己的心得。

       首先是设计数据库的表,一共5张表,分别为用户表,角色表,权限表,用户角色关系表,角色权限关系表。这里遇到的最大的坑就一个,导致后台程序被大改,这里给自己警醒,场景是这样的,当我手动从数据库中删除一条数据的时候,代码debug调试的时候竟然查到我删掉的数据,这是一件很诡异的事情,后来上网查了一些这方面的资料,虽然没查到我这个问题的原因,但是解决方案算是找到了,即为:一张表除了有一个数据库自带的自增主键,还要设定一个逻辑主键,可以用UUID作为主键。第二个问题是项目中的删除很少用到delete语句,一般都是软删除,即为添加一个字段isDelete(0表示删除,1表示存在),所以删除即为更新一下这个字段即可。

       然后是后台程序方面:第一个肯定是登录操作,判断逻辑还是有点绕的,首先根据用户名查该用户是否存在,如果不存在,即返回给前端错误码和错误信息;如果查到的话,再将查到的用户的密码和前台传过来的密码进行比对,如果不等,那么进行三次机会重新输入,如果都输入错误,则将该用户的状态更新为锁定,表示该用户暂时不能登录;如果该用户密码比对正确或者三次机会中有一次机会输入正确,则表示该用户登陆成功,更新该用户数据库密码错误次数为初始值。然后用该用户主键根据角色用户关系表查询该用户的角色,为一个集合,再用该角色的主键根据角色权限关系表查询该角色的权限信息,为一个list,然后用该用户的唯一标识,比如该用户的编号,拼接一个随机数,生成一个token,然后将该用户信息和权限的list集合以及这个token封装到一个对象中,返给前台,还将这个信息存在redis缓存中,当然还有个自定义的本地缓存,怎么创建,这样来:创建一个工具类,例如LocalCache类,然后在这个类中定义一个static的集合,例如:

                    private static List<缓存存储的对象> myList =  new ArrayList<>();

然后是用户类和角色类的增删改查,删除数据改isDelete状态,修改数据后返回修改后的数据信息,这些没什么好说的,新增数据的时候要注意先查一下,如果数据库中有这条数据的话,那么不让增加。代码需要try{}catch(){},这样出现错误也能够捕捉的到。区别权限的菜单级和按钮级,这个很好区别,根据Controller的@RequestMapping("")中的path很好判断。例如:

然后还有根据日期区间进行查询,例如查询当天的数据,例如查询2018-12-12 00:00:00到2018-12-12 23:59:59这个日期区间的数据,但是前台传给你的只有2018-12-12日这个格式的数据,因此需要你进行转换为你所需要的日期形式,如下:

package com.Jevin.controller;import org.junit.Test;import java.util.Calendar;import java.util.Date;public class DateUtil {    /**     * 获取日期的00:00:00     * @param startDate     * @return     */    public static Date getStartTime(Date startDate){        Calendar calendar = Calendar.getInstance();        calendar.setTime(startDate);        calendar.set(Calendar.HOUR_OF_DAY,0);        calendar.set(Calendar.MINUTE,0);        calendar.set(Calendar.SECOND,0);        return calendar.getTime();    }    /**     * 获取日期的23:59:59     * @param endDate     * @return     */    public static Date getEndTime(Date endDate){        Calendar calendar = Calendar.getInstance();        calendar.setTime(endDate);        calendar.set(Calendar.HOUR_OF_DAY,23);        calendar.set(Calendar.MINUTE,59);        calendar.set(Calendar.SECOND,59);        return calendar.getTime();    }    @Test    public void test(){        System.out.println(getEndTime(new Date()));    }}

然后就是对象封装的问题,即为同一个类,我们需要将其拆分为三个对象,一个用来接收前台的参数,一个对象用来和数据库进行交互,一个对象用来返回给前端。

然后是过滤器的问题,到目前为止我已经试过4中过滤器了:

第一种是springAOP过滤器:

package com.Jevin.controller;import org.aopalliance.intercept.MethodInterceptor;import org.aopalliance.intercept.MethodInvocation;public class PermissionInterceptor implements MethodInterceptor {        @Override    public Object invoke(MethodInvocation methodInvocation) throws Throwable {        System.out.println("进入过滤器");        return methodInvocation.proceed();    }}

配置文件

userController
permissionInterceptor

第二种是jboss.resteasy中的CorsFilter

导入一下依赖

org.jboss.resteasy
resteasy-jaxrs
3.0.12.Final
package com.Jevin.controller;import org.jboss.resteasy.plugins.interceptors.CorsFilter;import javax.ws.rs.container.ContainerRequestContext;import javax.ws.rs.container.PreMatching;import javax.ws.rs.core.MediaType;import javax.ws.rs.core.Response;import javax.ws.rs.ext.Provider;import java.io.IOException;@Provider@PreMatchingpublic class PermissionFilter extends CorsFilter {    @Override    public void filter(ContainerRequestContext requestContext) throws IOException {        System.out.println("requestContext");        boolean flag = false;        if(!flag){            Result result = new Result();            result.setResponseCode("000");            result.setReserveMsg("error message");            Response.ResponseBuilder builder = Response.status(200).entity(result);            builder.type(MediaType.APPLICATION_JSON);            requestContext.abortWith(builder.build());        }    }}

其中Result是一个结果集对象,主要用来返回给前端响应结果的。

第三种是javax.servlet.Filter中的doFilter()方法过滤器,

第四种是org.springframework.web.servlet.HandlerInterceptor,

这两种比较常见,在网上随处可以查到一大把,这里就不说了。

然后是用户状态,比方说0表示正常,1表示销户,2表示锁定,0,1,2是插入数据库中的数据;正常,销户,锁定是返回给前端的用户状态信息,这里最好用enum枚举类型来做,如下:

package com.Jevin.controller;public enum UserStateEnum {    NORMAL("0","正常"),    CANCEL("1","注销"),    LOCK("2","锁定");    private String code;    private String status;    UserStateEnum(String code,String status){        this.code=code;        this.status=status;    }    public String getCode() {        return code;    }    public void setCode(String code) {        this.code = code;    }    public String getStatus() {        return status;    }    public void setStatus(String status) {        this.status = status;    }}

大致自己所走过的弯路,所总结的也就这些了,希望给道友一些友好的提示。。。

后来这里做过一套shiro的权限系统,这里也做一下总结:

实体类三个:

package cn.coralglobal.model.po.admin;import org.hibernate.validator.constraints.NotEmpty;import javax.validation.constraints.Size;import java.io.Serializable;import java.util.Date;import java.util.HashSet;import java.util.List;import java.util.Set;import lombok.Data;@Datapublic class AdminAccount implements Serializable {    private String id;    @NotEmpty(message = "用户名不能为空")    private String name;    @NotEmpty(message = "密码不能为空")    @Size(min = 3, max = 20, message = "密码长度为3到20位")    private String password;    private Date createTime;    private List
roleList; //一个用户对应多个角色}
package cn.coralglobal.model.po.admin;import lombok.Data;import java.util.Date;import java.util.List;@Datapublic class AdminRole implements java.io.Serializable {    private String id;    private String name;    private String description;    private Date createTime;    private List
permissionList;// 一个角色对应多个权限}
package cn.coralglobal.model.po.admin;import lombok.Data;import java.util.Date;@Datapublic class AdminPermission implements java.io.Serializable {    private String id;    private String name;    private String description;    private Date createTime;}

数据库设计如下:

用户表:

CREATE TABLE `admin_account` (  `id` varchar(30) NOT NULL,  `name` varchar(50) NOT NULL,  `password` varchar(50) NOT NULL,  `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,  PRIMARY KEY (`id`) USING BTREE) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT '用户表';

用户角色表

CREATE TABLE `admin_account_role` (  `account_id` varchar(30) NOT NULL COMMENT '用户id',  `role_id` varchar(30) NOT NULL COMMENT '角色id') ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT '用户角色对应表';

角色表

CREATE TABLE `admin_role` (  `id` varchar(30) NOT NULL,  `name` varchar(50) NOT NULL,  `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,  `description` varchar(250) DEFAULT NULL COMMENT '描述',  PRIMARY KEY (`id`) USING BTREE) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT '角色表';

角色权限表

CREATE TABLE `admin_role_permission` (  `role_id` varchar(30) NOT NULL COMMENT '角色id',  `permission_id` varchar(30) NOT NULL COMMENT '权限id') ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT '角色权限对应表';

权限表

CREATE TABLE `admin_permission` (  `id` varchar(30) NOT NULL,  `name` varchar(50) NOT NULL,  `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,  `description` varchar(250) DEFAULT NULL COMMENT '描述',  PRIMARY KEY (`id`) USING BTREE) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT '权限表';

mapper文件如下:

a.id, a.name, a.password, a.create_time, r.id AS role_id, r.name AS role_name, r.create_time as role_create_time
r.id, r.name, r.create_time, p.id AS permission_id, p.name AS permission_name, p.create_time AS permission_create_time

认证和授权如下

package cn.coralglobal.admin.config;import cn.coralglobal.dal.mapper.AdminAccountMapper;import cn.coralglobal.dal.mapper.AdminRoleMapper;import cn.coralglobal.model.po.admin.AdminAccount;import cn.coralglobal.model.po.admin.AdminPermission;import cn.coralglobal.model.po.admin.AdminRole;import org.apache.shiro.authc.*;import org.apache.shiro.authz.AuthorizationInfo;import org.apache.shiro.authz.SimpleAuthorizationInfo;import org.apache.shiro.realm.AuthorizingRealm;import org.apache.shiro.subject.PrincipalCollection;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;import java.util.ArrayList;import java.util.List;public class UserAuthRealm extends AuthorizingRealm {    private static final Logger logger = LoggerFactory.getLogger(UserAuthRealm.class);    @Autowired    private AdminAccountMapper adminAccountMapper;    @Autowired    private AdminRoleMapper adminRoleMapper;    /**     * 授权     *     * @param principalCollection     * @return     */    @Override    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {//        Object primaryPrincipal = principalCollection.getPrimaryPrincipal();//        AdminAccount adminAccount = (AdminAccount) primaryPrincipal;//        System.out.println("adminAccount:" + adminAccount);        String userName = (String) principalCollection.fromRealm(this.getClass().getName()).iterator().next();        AdminAccount account = adminAccountMapper.selectByName(userName);        List
roleList = account.getRoleList(); AdminRole adminRole = roleList.get(0); adminRole = adminRoleMapper.selectByName(adminRole.getName());// AdminRole adminRole = adminRoleMapper.selectByName(userName); List
permissionList = adminRole.getPermissionList(); List
permissions = new ArrayList<>(); if (permissionList.size() > 0) { for (AdminPermission permission : permissionList) { permissions.add(permission.getName()); } } SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); info.addRole(adminRole.getName()); info.addStringPermissions(permissions); return info; } /** * 认证登录 * * @param token * @return * @throws AuthenticationException */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) token; String loginName = usernamePasswordToken.getUsername(); AdminAccount adminAccount = adminAccountMapper.selectByName(loginName); if (adminAccount == null) { throw new UnknownAccountException(); } List
roleList = adminAccount.getRoleList(); //获取用户角色 List
permissionList = new ArrayList<>(); for (AdminRole roleList1 : roleList) { List
permissionList1 = adminRoleMapper.selectByPrimaryKey(roleList1.getId()).getPermissionList(); //获取用户权限 permissionList.addAll(permissionList1); roleList1.setPermissionList(permissionList1); } adminAccount.setRoleList(roleList); System.out.println("============" + adminAccount.getRoleList()); return new SimpleAuthenticationInfo(adminAccount.getName(), adminAccount.getPassword(), this.getClass().getName()); }}

登陆核心代码也就几行:

 退出的话,代码也很简单,如下

 前端页面权限控制可用如下标签:

当然,也可用<@shiro.hasRole name=""></@shiro.hasRole>

你可能感兴趣的文章
ADO.NET Ling to Sql 语法
查看>>
ASP.NET MVC 2博客系列之一:强类型HTML辅助方法
查看>>
详解Asp.net MVC DropDownLists
查看>>
Asp.net MVC防止图片盗链的实现方法,通过自定义RouteHandler来操作
查看>>
VS2010的智能提示没有了的可能原因
查看>>
Creating a Cascading Dropdown in ASP.net MVC 3 and jQuery (1)
查看>>
创建联动的 DropdownList in ASP.net MVC 3 and jQuery (2)
查看>>
HTTP触发Jenkins参数化构建(CORS Plugin)
查看>>
来自 Serenity 的 Java 8 的一些使用技巧
查看>>
ubuntu12.04--子进程 已安装 post-installation 脚本 返回了错误号 1
查看>>
系统--电脑开机一声长响
查看>>
系统--A disk read error occurred Press Ctrl+Alt+d...
查看>>
Some projects cannot be imported because they a...
查看>>
ubuntu-android--make: *** [out/host/linux-x86/o...
查看>>
原子变量与synchronized详细解释
查看>>
java.lang.OutOfMemoryError: PermGen space及其解决方法
查看>>
如何让ajaxfileupload.js支持IE9,IE10,并可以传递多个参数?
查看>>
highcharts扩展tooltip提示异步信息
查看>>
activiti--History 历史配置
查看>>
activiti--部署bpmn/bar文件详解
查看>>