侧边栏壁纸
博主头像
落叶人生博主等级

走进秋风,寻找秋天的落叶

  • 累计撰写 130562 篇文章
  • 累计创建 28 个标签
  • 累计收到 9 条评论
标签搜索

目 录CONTENT

文章目录

基于shiro的按钮级别的权限管理系统

2023-12-12 星期二 / 0 评论 / 0 点赞 / 42 阅读 / 55197 字

一、项目背景 作为程序猿的你,是否在大学课堂上听到老师讲权限管理一脸懵逼;是否在互联网上看到炫酷的权限管理系统一脸羡慕;是否在公司学习使用权限管理一脸激动。那么,今天你看到这个教程之后,请你不要再懵逼

一、项目背景

    作为程序猿的你,是否在大学课堂上听到老师讲权限管理一脸懵逼;是否在互联网上看到炫酷的权限管理系统一脸羡慕;是否在公司学习使用权限管理一脸激动。那么,今天你看到这个教程之后,请你不要再懵逼,请不要再羡慕,请肆无忌惮的激动吧。好嗨哟,即将带你走上人生的巅峰。下面将手把手的教你实现基于shiro权限框架的权限管理系统,真正意义上的在按钮级别上完成权限控制。注:本教程侧重点在于shiro框架的使用与权限控制逻辑的实现,对于其它知识点不在重点讨论范围内。如需学习更多关于shiro的知识可在我的文章查看。

二、技术栈

    后台:spring+springmvc+mybatis+shiro+kaptcha+fastjson+log4j+druid+maven+echcache+pageHelper等

    前端:vue+jquery+iview+ztree等

    数据库:mysql

    其它:IntelliJ IDEA 2018.2.4 x64+tomcat8.0+jdk1.8

三、项目结构

四、项目预览

                                                        图1    登录首页

                                                        图2    系统首页

                                                            图3    用户列表

                                                        图4    用户新增

                                                            图5    角色列表

                                                        图6    角色新增

                                                        图7    菜单列表

                                                        图8    菜单新增

五、数据库设计

    权限管理系统基础表有五张:sys_user(用户表)、sys_role(角色表)、sys_menu(资源表)、sys_user_role(用户角色关联表)、sys_role_menu(角色资源关联表),用户与角色和角色与资源都是多对多的关系,用户与资源必须通过授予角色才能建立关系。

(1)用户表详细设计

(2)角色表详细设计

(3)资源表详细设计

(4)用户角色表详细设计

(5)角色资源表详细设计

六、功能设计

(1)角色授权

        此处新建一个角色为“测试”,授予用户管理菜单权限、新增按钮权限、删除按钮权限。

(2)分配角色

        此处新增新建一个用户“a”,分配“测试”角色。

(3)新用户登录测试

    因为“a”用户分配的角色为“测试”,“测试”角色拥有用户管理菜单、新增按钮、删除按钮权限,用该用户登录系统后只能看到用户管理菜单、新增按钮、删除按钮;不会看到其它的系统菜单和修改按钮。        

七、项目代码示例

        该项目的基础代码github地址为:https://github.com/tmAlj/shiro/tree/master/ssms,以下的给出的配置文件为本项目改变的内容,其余相同的部分未给出。

(1)pom.xml依赖管理配置

<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0"         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">    <modelVersion>4.0.0</modelVersion>    <groupId>com.wsd</groupId>    <artifactId>ssms1</artifactId>    <version>1.0-SNAPSHOT</version>    <build>        <plugins>            <plugin>                <groupId>org.apache.maven.plugins</groupId>                <artifactId>maven-compiler-plugin</artifactId>                <configuration>                    <source>7</source>                    <target>7</target>                </configuration>            </plugin>        </plugins>    </build>    <dependencies>        <!-- spring依赖 -->        <dependency>            <groupId>org.springframework</groupId>            <artifactId>spring-core</artifactId>            <version>4.3.3.RELEASE</version>        </dependency>        <dependency>            <groupId>org.springframework</groupId>            <artifactId>spring-context</artifactId>            <version>4.3.3.RELEASE</version>        </dependency>        <dependency>            <groupId>org.springframework</groupId>            <artifactId>spring-aspects</artifactId>            <version>4.3.3.RELEASE</version>        </dependency>        <dependency>            <groupId>org.springframework</groupId>            <artifactId>spring-context-support</artifactId>            <version>4.3.3.RELEASE</version>        </dependency>        <dependency>            <groupId>org.springframework</groupId>            <artifactId>spring-beans</artifactId>            <version>4.3.3.RELEASE</version>        </dependency>        <dependency>            <groupId>org.springframework</groupId>            <artifactId>spring-expression</artifactId>            <version>4.3.3.RELEASE</version>        </dependency>        <dependency>            <groupId>org.springframework</groupId>            <artifactId>spring-jdbc</artifactId>            <version>4.3.3.RELEASE</version>        </dependency>        <dependency>            <groupId>org.springframework</groupId>            <artifactId>spring-tx</artifactId>            <version>4.3.3.RELEASE</version>        </dependency>        <!-- end -->        <!-- mysql依赖 -->        <dependency>            <groupId>mysql</groupId>            <artifactId>mysql-connector-java</artifactId>            <version>5.1.40</version>        </dependency>        <!-- end -->        <!-- 数据源依赖 -->        <dependency>            <groupId>com.alibaba</groupId>            <artifactId>druid</artifactId>            <version>1.0.26</version>        </dependency>        <!-- end -->        <!-- mybatis依赖 -->        <dependency>            <groupId>org.mybatis</groupId>            <artifactId>mybatis</artifactId>            <version>3.4.1</version>        </dependency>        <dependency>            <groupId>org.mybatis</groupId>            <artifactId>mybatis-spring</artifactId>            <version>1.3.0</version>        </dependency>        <dependency>            <groupId>com.github.pagehelper</groupId>            <artifactId>pagehelper</artifactId>            <version>4.1.6</version>        </dependency>        <!-- end -->        <!-- springMVC依赖 -->        <dependency>            <groupId>org.springframework</groupId>            <artifactId>spring-webmvc</artifactId>            <version>4.3.3.RELEASE</version>        </dependency>        <dependency>            <groupId>jstl</groupId>            <artifactId>jstl</artifactId>            <version>1.2</version>        </dependency>        <dependency>            <groupId>taglibs</groupId>            <artifactId>standard</artifactId>            <version>1.1.2</version>        </dependency>        <!-- springMVC依赖end -->        <!-- log4j依赖-->        <dependency>            <groupId>org.slf4j</groupId>            <artifactId>slf4j-api</artifactId>            <version>1.7.19</version>        </dependency>        <dependency>            <groupId>org.slf4j</groupId>            <artifactId>slf4j-log4j12</artifactId>            <version>1.7.19</version>        </dependency>        <dependency>            <groupId>log4j</groupId>            <artifactId>log4j</artifactId>            <version>1.2.17</version>        </dependency>        <!-- end -->        <!-- junit单元测试依赖 -->        <dependency>            <groupId>junit</groupId>            <artifactId>junit</artifactId>            <version>4.12</version>        </dependency>        <!-- end -->        <!-- fastjson依赖 -->        <dependency>            <groupId>com.alibaba</groupId>            <artifactId>fastjson</artifactId>            <version>1.2.20</version>        </dependency>        <!-- end -->        <!-- servlet依赖 -->        <dependency>            <groupId>javax.servlet</groupId>            <artifactId>javax.servlet-api</artifactId>            <version>3.1.0</version>        </dependency>        <!-- end -->        <!-- commons相关依赖 -->        <dependency>            <groupId>commons-codec</groupId>            <artifactId>commons-codec</artifactId>            <version>1.10</version>        </dependency>        <dependency>            <groupId>commons-configuration</groupId>            <artifactId>commons-configuration</artifactId>            <version>1.10</version>        </dependency>        <dependency>            <groupId>commons-lang</groupId>            <artifactId>commons-lang</artifactId>            <version>2.6</version>        </dependency>        <dependency>            <groupId>commons-fileupload</groupId>            <artifactId>commons-fileupload</artifactId>            <version>1.3.1</version>        </dependency>        <dependency>            <groupId>commons-io</groupId>            <artifactId>commons-io</artifactId>            <version>2.5</version>        </dependency>        <dependency>            <groupId>commons-logging</groupId>            <artifactId>commons-logging</artifactId>            <version>1.2</version>        </dependency>        <!-- end -->        <!-- shiro依赖 -->        <dependency>            <groupId>org.apache.shiro</groupId>            <artifactId>shiro-core</artifactId>            <version>1.3.2</version>        </dependency>        <dependency>            <groupId>org.apache.shiro</groupId>            <artifactId>shiro-ehcache</artifactId>            <version>1.3.2</version>        </dependency>        <dependency>            <groupId>org.apache.shiro</groupId>            <artifactId>shiro-spring</artifactId>            <version>1.3.2</version>        </dependency>        <dependency>            <groupId>org.apache.shiro</groupId>            <artifactId>shiro-web</artifactId>            <version>1.3.2</version>        </dependency>        <!-- end -->        <!-- kaptcha验证码start -->        <dependency>            <groupId>com.github.axet</groupId>            <artifactId>kaptcha</artifactId>            <version>0.0.9</version>        </dependency>        <!-- end -->    </dependencies>    </project>

(2)web.xml配置

<?xml version="1.0" encoding="UTF-8"?><web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"         version="4.0">        <!--项目启动首页配置-->        <display-name>tm-cli</display-name>        <welcome-file-list>            <welcome-file>login.jsp</welcome-file>        </welcome-file-list>        <!-- 定义上下文,扫描spring配置文件 -->        <context-param>            <param-name>contextConfigLocation</param-name>            <param-value>                classpath:spring-config.xml            </param-value>        </context-param>        <listener>            <listener-class>org.springframework.web.context.ContextLoaderListener            </listener-class>        </listener>        <!-- 统一编码过滤器配置 -->        <filter>            <filter-name>encode</filter-name>            <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>            <init-param>                <param-name>encoding</param-name>                <param-value>utf-8</param-value>            </init-param>        </filter>        <filter-mapping>            <filter-name>encode</filter-name>            <url-pattern>/*</url-pattern>        </filter-mapping>        <!-- springMVC前段控制器配置 -->        <servlet>            <servlet-name>appServlet</servlet-name>            <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>            <init-param>                <param-name>contextConfigLocation</param-name>                <param-value>classpath:spring-mvc-config.xml</param-value>            </init-param>            <load-on-startup>1</load-on-startup>            <async-supported>true</async-supported>        </servlet>        <servlet-mapping>            <servlet-name>appServlet</servlet-name>            <url-pattern>/</url-pattern>        </servlet-mapping>        <!-- shiro过滤器配置 -->        <filter>            <filter-name>shiroFilter</filter-name>            <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>            <init-param>                <param-name>targetFilterLifecycle</param-name>                <param-value>true</param-value>            </init-param>        </filter>        <filter-mapping>            <filter-name>shiroFilter</filter-name>            <url-pattern>/*</url-pattern>        </filter-mapping></web-app>

(3)shiro配置文件spring-shiro-config.xml配置

<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"	   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"	   xsi:schemaLocation="       http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">	<!-- 配置自定义reaml -->	<bean id="loginRealm" class="com.wsd.shiro.LoginRealm"/>	<!-- 配置shiro的核心securityManager -->	<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">		<property name="cacheManager" ref="cacheManager"/>		<!-- 配置realm -->		<property name="realm" ref="loginRealm"/>		<!-- 配置记住我的时长 -->		<property name="rememberMeManager.cookie.maxAge" value="60"></property>	</bean>	<!-- 配置ehcache缓存 -->	<bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">        <property name="cacheManagerConfigFile" value="classpath:ehcache.xml"/>	</bean>	<!-- 配置shiro中bean生命周期管理器 -->	<bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>	<!-- AOP式方法级权限检查 -->	<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"		  depends-on="lifecycleBeanPostProcessor">		<property name="proxyTargetClass" value="true" />	</bean>	<bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">		<property name="securityManager" ref="securityManager"/>	</bean>	<!-- shiro过滤器配置,与web.xml中shiro过滤器同名 -->	<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">		<property name="securityManager" ref="securityManager"/>		<!-- 需要登录成功后跳转的页面 -->		<property name="loginUrl" value="/login.jsp"/>		<!-- 登录成功后跳转的页面 -->		<property name="successUrl" value="/index.jsp"/>		<!-- 访问未授权页面跳转的页面 -->		<property name="unauthorizedUrl" value="/unauthor.html"/>			<property name="filterChainDefinitions">			<!-- 静态资源需要设置为anon,否则找不到 -->			<value>				/statics/** = anon				/plugins/** = anon				/login.jsp = anon				/login = anon				/logout = logout				/captcha.jpg = anon				/** = authc			</value>		</property>	</bean></beans>

(4)springmvc配置文件spring-mvc-config.xml配置

<beans xmlns="http://www.springframework.org/schema/beans"       xmlns:context="http://www.springframework.org/schema/context"       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"       xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:aop="http://www.springframework.org/schema/aop"       xsi:schemaLocation="http://www.springframework.org/schema/beans        http://www.springframework.org/schema/beans/spring-beans-4.0.xsd        http://www.springframework.org/schema/mvc        http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd        http://www.springframework.org/schema/context        http://www.springframework.org/schema/context/spring-context-4.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">    <!--视图解析器,如访问Controller中配置的"/tm",系统会自动找到路径为prefix后缀为suffix的文件并解析  -->    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">        <property name="viewClass"                  value="org.springframework.web.servlet.view.JstlView"></property>        <property name="prefix" value="/WEB-INF/pages/"></property>        <property name="suffix" value=".jsp"></property>    </bean>    <!-- 使用零配置 -->    <context:component-scan base-package="com.wsd" />    <mvc:default-servlet-handler />    <mvc:annotation-driven />    <!-- 配置interceptor拦截器 -->    <mvc:interceptors>        <!-- 默认拦截所有请求 -->        <bean class="com.wsd.interceptor.Interceptor"/>    </mvc:interceptors>    <!-- 开启shiro中aop注解 -->    <aop:config proxy-target-class="true"></aop:config>    <!--配置fastjson,返回json数据格式-->    <mvc:annotation-driven>        <mvc:message-converters register-defaults="true">            <!-- 配置Fastjson支持 -->            <bean class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter">                <property name="supportedMediaTypes">                    <list>                        <value>application/json;charset=UTF-8</value>                        <value>text/html;charset=UTF-8</value>                    </list>                </property>                <property name="features">                    <list>                        <value>WriteMapNullValue</value>                        <value>QuoteFieldNames</value>                    </list>                </property>            </bean>        </mvc:message-converters>    </mvc:annotation-driven>    <!-- 配置kaptcha验证码生成器 -->    <bean name="producer" class="com.google.code.kaptcha.impl.DefaultKaptcha" scope="singleton">        <property name="config">            <bean class="com.google.code.kaptcha.util.Config">                <constructor-arg>                    <props>                        <prop key="kaptcha.border">no</prop>                        <prop key="kaptcha.textproducer.font.color">black</prop>                        <prop key="kaptcha.textproducer.char.space">5</prop>                    </props>                </constructor-arg>            </bean>        </property>    </bean></beans>

八、部分功能解析

(1)登录认证(认证参考)

        1.1    前端实现

<%@ page contentType="text/html;charset=UTF-8" language="java" %><!DOCTYPE html><html><head>    <meta charset="utf-8">    <meta http-equiv="X-UA-Compatible" content="IE=edge">    <meta content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" name="viewport">    <title>用户登录</title>    <link rel="stylesheet" type="text/css" href="statics/css/iview.css">    <link rel="stylesheet" type="text/css" href="statics/css/login.css" /></head><body>    <div id="app" v-cloak>        <div class="tm-title">欢迎使用tm-cli管理系统</div>        <div class="tm-content">            <i-input prefix="ios-contact" placeholder="账号" class="tm-input" v-model="account"></i-input>            <i-input prefix="md-lock" placeholder="密码" class="tm-input" type="password" v-model="password"></i-input>            <i-input prefix="ios-analytics" placeholder="验证码"  class="tm-input" v-model="code"></i-input>            <div class="tm-code">                <div class="tm-picture">                    <img alt="点击刷新"  :src="src" @click="onRefrCodeEvet()" class="tm-img">                </div>                <div class="tm-reflush" @click="onRefrCodeEvet()">点击刷新</div>            </div>            <i-button type="primary" long :loading="loading" @click="callLoginImpl()">登&nbsp;&nbsp;&nbsp;&nbsp;录</i-button>            <div class="tm-footer">                <div class="tm-checkbox">                    <checkbox v-model="remember"></checkbox>                </div>                <div class="tm-remember">                    记住我                </div>                <div class="tm-forget">                    忘记密码?                </div>            </div>        </div>        <div class="tm-copyright">Copyright © 2018 All Rights Reserved</div>    </div>    <script type="text/javascript" src="statics/js/jquery-3.2.1.js"></script>    <script type="text/javascript" src="statics/js/vue.min.js"></script>    <script type="text/javascript" src="statics/js/iview.min.js"></script>    <script>        new Vue({            el: '#app',            data: {                account: '', //账号                password: '', //密码                code: '', //验证码                src: 'captcha.jpg', //验证码图片                loading: false, //登录按钮加载动画                remember: false, //记住我复选框                msg: '' //提示信息            },            methods: {                /*调用登录接口*/                callLoginImpl: function(){                    var t = this;                    if(t.doCheckFormFun()){                        t.loading = true;                        var data = "account="+this.account+"&password="+this.password+"&code="+this.code+"&remember="+this.remember;                        $.ajax({                            type: "POST",                            url: "login",                            data: data,                            dataType: "json",                            success: function(data){                                if(data.code == 0){ //登录成功                                    t.loading = false;                                    parent.location.href ='index.jsp';                                }else{                                    t.msg = data.msg;                                    t.$Message.warning(t.msg);                                    t.onRefrCodeEvet();                                    t.loading = false;                                }                            }                        });                    }                },                /*刷新验证码点击事件*/                onRefrCodeEvet: function(){                    var t = this;                    t.src = "captcha.jpg?t=" + $.now();                },                /*表单验证方法*/                doCheckFormFun: function(){                    var t = this;                    if(t.account == '' || t.account == undefined){                        t.$Message.warning("账户输入不能为空!");                        return false;                    }                    else if(t.password == '' || t.password == undefined){                        t.$Message.warning("密码输入不能为空!");                        return false;                    }                    else if(t.code == '' || t.code == undefined){                        t.$Message.warning("验证码输入不能为空!");                        return false;                    }else{                        return true;                    }                }            }        })    </script></body></html>

        1.2    controller实现

package com.wsd.controller;import com.google.code.kaptcha.Constants;import com.google.code.kaptcha.Producer;import com.wsd.utils.ResultData;import com.wsd.utils.ShiroUtils;import org.apache.shiro.authc.*;import org.apache.shiro.crypto.hash.Sha256Hash;import org.apache.shiro.subject.Subject;import org.springframework.beans.factory.annotation.Autowired;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 javax.imageio.ImageIO;import javax.servlet.ServletException;import javax.servlet.ServletOutputStream;import javax.servlet.http.HttpServletResponse;import java.awt.image.BufferedImage;import java.io.IOException;/** * Created by tm on 2018/8/26. * 登录controller */@Controller()public class LoginController {    @Autowired    private Producer producer; //验证码操作对象    /**     * 生成验证码     * @param response     * @throws ServletException     * @throws IOException     */    @RequestMapping("captcha.jpg")    public void captcha(HttpServletResponse response)throws ServletException, IOException {        //页面不用缓存        response.setHeader("Cache-Control", "no-store, no-cache");        response.setContentType("image/jpeg");        //生成文字验证码        String text = producer.createText();        //生成图片验证码        BufferedImage image = producer.createImage(text);        //验证码存入session,用于登录时做对比        ShiroUtils.setSessionAttribute(Constants.KAPTCHA_SESSION_KEY, text);        ServletOutputStream out = response.getOutputStream();        //输出验证码        ImageIO.write(image, "jpg", out);    }    /**     * 登录     */    @ResponseBody    @RequestMapping(value = "/login", method = RequestMethod.POST)    public ResultData login(String account, String password, String code, String remember)throws IOException {        String kaptcha = ShiroUtils.getKaptcha(Constants.KAPTCHA_SESSION_KEY); //session中获取保存的验证码内容        if(!kaptcha.equalsIgnoreCase(code)){            return ResultData.error("验证码不正确");        }        try{            Subject subject = ShiroUtils.getSubject();            password = new Sha256Hash(password).toHex();            UsernamePasswordToken token = new UsernamePasswordToken(account, password);            // 开启记住我的功能            if(remember.equals("false")){                token.setRememberMe(false);            }else{                token.setRememberMe(true);            }            subject.login(token);        }catch (UnknownAccountException e) {            return ResultData.error(e.getMessage());        }catch (IncorrectCredentialsException e) {            return ResultData.error(e.getMessage());        }catch (LockedAccountException e) {            return ResultData.error(e.getMessage());        }catch (AuthenticationException e) {            return ResultData.error("账户验证失败");        }catch (Exception e) {            return ResultData.error();        }        return ResultData.ok();    }}

        1.3    自定义loginRealm

package com.wsd.shiro;import com.wsd.model.Menu;import com.wsd.model.User;import com.wsd.service.MenuService;import com.wsd.service.UserService;import com.wsd.service.impl.LoginServiceImpl;import com.wsd.service.impl.MenuServiceImpl;import com.wsd.service.impl.UserServiceImpl;import org.apache.commons.lang.StringUtils;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.springframework.beans.factory.annotation.Autowired;import java.util.*;/** * Created by tm on 2018/8/26. * 自定义realm * 注:需要在spring-shiro-config.xml中配置 */public class LoginRealm extends AuthorizingRealm {    @Autowired LoginServiceImpl lsi; //注入登录service    @Autowired MenuServiceImpl msi; //注入菜单service    @Autowired UserServiceImpl usi; //注入用户service    /*授权*/    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {        User user = (User)principalCollection.getPrimaryPrincipal();        Long userId = user.getUserId();        List<String> permsList = null;        //系统管理员,拥有最高权限        if(userId == 1){            List<Menu> menuList = msi.queryList(new HashMap<String, Object>());            permsList = new ArrayList<String>(menuList.size());            for(Menu menu : menuList){                permsList.add(menu.getPerms());            }        }else{            permsList = usi.queryAllPerms(userId);        }        //用户权限列表        Set<String> permsSet = new HashSet<String>();        for(String perms : permsList){            if(StringUtils.isBlank(perms)){                continue;            }            permsSet.addAll(Arrays.asList(perms.trim().split(",")));        }        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();        info.setStringPermissions(permsSet);        return info;    }    /*验证*/    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {        String account = (String) authenticationToken.getPrincipal(); //获取输入的账户        String password = new String((char[]) authenticationToken.getCredentials()); //获取输入的密码        //数据中查询用户信息        User user = lsi.queryByUserName(account);        //账号不存在        if(user == null) {            throw new UnknownAccountException("账号或密码不正确");        }        //密码错误        if(!password.equals(user.getPassword())) {            throw new IncorrectCredentialsException("账号或密码不正确");        }        //账号锁定        if(user.getStatus() == 0){            throw new LockedAccountException("账号已被锁定,请联系管理员");        }        SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, password, getName());        return info;    }}

    (2)权限控制(授权参考)

            2.1    前端实现(通过shiro的标签控制前端权限标签参考)

<%@ page contentType="text/html;charset=UTF-8" language="java" %><%@taglib prefix="shiro" uri="http://shiro.apache.org/tags" %><!DOCTYPE html><html><head>    <meta charset="utf-8">    <meta http-equiv="X-UA-Compatible" content="IE=edge">    <meta content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" name="viewport">    <title>用户管理</title>    <link rel="stylesheet" type="text/css" href="${pageContext.request.contextPath}/statics/css/iview.css">    <link rel="stylesheet" type="text/css" href="${pageContext.request.contextPath}/statics/css/index.css"></head><body>    <div id="app" v-cloak>        <!--操作按钮-->        <div class="tm-btns">            <shiro:hasPermission name="sys:user:save">                <i-button type="info" @click="onAddEvet()">新增</i-button>            </shiro:hasPermission>            <shiro:hasPermission name="sys:user:update">                <i-button type="primary" @click="onUpdateEvet()">修改</i-button>            </shiro:hasPermission>            <shiro:hasPermission name="sys:user:delete">                <i-button type="warning" @click="onDeleteAllEvet()">删除</i-button>            </shiro:hasPermission>            <shiro:hasPermission name="sys:user:list">            <div class="tm-btns-search">                <i-input placeholder="输入用户名" style="width: 110px" v-model="userName" @keyup.enter.native="doSearchEvet">                    <icon type="ios-search" slot="suffix" @click="doSearchEvet()"></icon>                </i-input>            </div>            </shiro:hasPermission>        </div>        <!--表格-->        <shiro:hasPermission name="sys:user:list">            <i-table border :loading="loading" :columns="columns" size="small" :data="datas" :height="433" @on-selection-change="onSeltChangeEvet"></i-table>        </shiro:hasPermission>        <!--分页-->        <shiro:hasPermission name="sys:user:list">            <div class="tm-page" v-if="pageShow">                <page :total="total" show-sizer show-total size="small" @on-change="onChangePageEvet" @on-page-size-change="onChangeSizeEvet"/>            </div>        </shiro:hasPermission>    </div>    <script type="text/javascript" src="${pageContext.request.contextPath}/statics/js/jquery-3.2.1.js"></script>    <script type="text/javascript" src="${pageContext.request.contextPath}/statics/js/vue.min.js"></script>    <script type="text/javascript" src="${pageContext.request.contextPath}/statics/js/iview.min.js"></script>    <script>        var vm = new Vue({            el: '#app',            data: {                loading: false, //表格加载动画                page: '1', //当前页码                limit: '10', //每页显示条数                pageShow: false, //是否显示分页标志                total: '', //数据总数                userName: '', //用户搜索框内容                parentVue: '', //父级vue对象,主要为了消息提示框的全局显示                checkList: [], //复选框保存值数组                userIdList: [], //用户id数组                columns: [	//表格头部数据                    {                        width: 50,                        type: 'selection',                        title: '',                        key: 'select'                    },                    {                        type: 'index',                        width: 70,                        title: '序号'                    },                    {                        width: 120,                        title: '用户名',                        key: 'username'                    },                    {                        width: 120,                        title: '手机号码',                        key: 'mobile'                    },                    {                        width: 120,                        title: '状态',                        key: 'status',                        render: function(h, params){                            var row = params.row;                            var color = row.status === 0 ? 'error' : 'success';                            var text = row.status === 0 ? '禁用' : '正常';                            return h('Tag', {                                props: {                                    type: 'dot',                                    color: color                                }                            }, text);                        }                    },                    {                        title: '邮箱',                        key: 'email'                    },                    {                        title: '创建时间',                        key: 'createTime',                        sortable: true,                        render: (h,params)=>{                            return h('div',                                vm.doFormatDateFun(new Date(params.row.createTime),'yyyy-MM-dd hh:mm:ss')                            )                        }                    }                ],                datas: [] //表格数据            },            methods: {                /*调用查询用户列表接口*/                callGetUserListImpl: function(){                    var p = this.parentVue;                    var t = this;                    t.loading = true; //打开加载动画                    var data = "page="+t.page+"&limit="+t.limit+"&userName="+t.userName;                    $.ajax({                        type: "POST",                        url: "../sys/user/list",                        data: data,                        dataType: "json",                        success: function(data){                            if(data.code == 0){                                //当数量超过10时,显示分页条                               if(data.page.total > 10){                                   t.total = data.page.total;                                   t.pageShow = true;                                }                                t.datas = data.page.list;                                t.loading = false;                            }                        },                        error: function () {                            t.loading = false;                            p.$Message.error("系统异常,请稍后重试!");                        }                    });                },                /*调用删除用户接口*/                callDeleteUserImpl: function(){                    var p = this.parentVue;                    var t = this;                    t.loading = true; //打开加载动画                    $.ajax({                        type: "POST",                        url: "../sys/user/delete",                        data: JSON.stringify(t.userIdList),                        dataType: "json",                        contentType:"application/json",                        success: function(data){                            t.loading = false;                            if(data.code == 0){                                p.$Message.success('操作成功!');                                t.callGetUserListImpl();                            }else{                                p.$Message.error(data.msg);                            }                        },                        error: function () {                            t.loading = false;                            p.$Message.error("系统异常,请稍后重试!");                        }                    });                },                /*添加按钮点击事件*/                onAddEvet: function(){                    var p = this.parentVue;                    p.url = "sys/user/user_add";                    p.title = "新增用户";                },                /*修改按钮点击事件*/                onUpdateEvet: function(){                    var p = this.parentVue;                    var t = this;                    if(t.userIdList.length != 1){                        p.$Message.warning('请选择一行您要修改的数据!');                    }else{                        p.url = "sys/user/user_add";                        p.title = "修改用户"; //传参                        p.userId = t.userIdList; //传参                    }                },                /*删除一行按钮点击事件*/                onDeleteEvet: function(item){                    var p = this.parentVue;                    var t = this;                    t.userIdList = []; //清空,避免数据重复                    /*系统提示框*/                    p.$Modal.confirm({                        title: '操作提示',                        content: '您确定删除所选项目吗?',                        onOk: function(){                            t.userIdList.push(item);                            t.callDeleteUserImpl();                        },                        onCancel: function(){}                    });                },                /*删除所有按钮点击事件*/                onDeleteAllEvet: function(){                    var p = this.parentVue;                    var t = this;                    if(this.userIdList.length == 0){                        p.$Message.warning('请选择您要删除的数据!');                    }else{                        /*系统提示框*/                        p.$Modal.confirm({                            title: '操作提示',                            content: '您确定删除所选项目吗?',                            onOk: function(){                                t.callDeleteUserImpl();                            },                            onCancel: function(){}                        });                    }                },                /*改变页码点击事件*/                onChangePageEvet: function(item){                    var t = this;                    t.page = item;                    t.callGetUserListImpl();                },                /*每页显示条数点击事件*/                onChangeSizeEvet: function(item){                    var t = this;                    t.limit = item;                    t.callGetUserListImpl();                },                /*搜索按钮点击事件*/                doSearchEvet: function (){                    var t = this;                    t.callGetUserListImpl();                },                /*多选行数据按钮点击事件*/                onSeltChangeEvet: function(item){                    var t = this;                    t.userIdList = []; //清空,避免数据重复                    if(item.length != 0){                        //获取多选用户ID数组                        for (var i = 0; i < item.length; i++){                            t.userIdList.push(item[i].userId)                        }                    }                },                /*日期格式化方法*/                doFormatDateFun: function(date, fmt) {                    var o = {                        'M+': date.getMonth() + 1, // 月份                        'd+': date.getDate(), // 日                        'h+': date.getHours(), // 小时                        'm+': date.getMinutes(), // 分                        's+': date.getSeconds(), // 秒                        'S': date.getMilliseconds() // 毫秒                    }                    if (/(y+)/.test(fmt)) {                        fmt = fmt.replace(RegExp.$1, (date.getFullYear() + '').substr(4 - RegExp.$1.length))                    }                    for (var k in o) {                        if (new RegExp('(' + k + ')').test(fmt)) {                            fmt = fmt.replace(RegExp.$1, (RegExp.$1.length === 1) ? (o[k]) : (('00' + o[k]).substr(('' + o[k]).length)))                        }                    }                    return fmt                }           },            created: function(){                var t = this;                t.callGetUserListImpl();                t.parentVue = parent.vm;            }        })    </script></body></html>

        2.2    controller实现(通过shiro的权限注解控制请求注解参考)

package com.wsd.controller;import com.github.pagehelper.PageHelper;import com.github.pagehelper.PageInfo;import com.wsd.base.BaseController;import com.wsd.model.User;import com.wsd.service.impl.LoginServiceImpl;import com.wsd.service.impl.UserAndRoleServiceImpl;import com.wsd.service.impl.UserServiceImpl;import com.wsd.utils.ResultData;import org.apache.commons.lang.ArrayUtils;import org.apache.commons.lang.StringUtils;import org.apache.shiro.authz.annotation.RequiresPermissions;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.*;import java.util.List;/** * Created by tm on 2018/8/26. * 系统用户controller */@Controller@RequestMapping("sys/user")public class UserController extends BaseController {    @Autowired UserServiceImpl usi; //注入系统用户service    @Autowired LoginServiceImpl lsi; //注入登录service    @Autowired UserAndRoleServiceImpl uarsi; //注入系统用户角色service    /**     * 访问user.jsp页面     * @return     */    @RequestMapping()    public String goUserPage(){        return "user";    }    /**     * 访问user_add.jsp页面     * @return     */    @RequestMapping("/user_add")    public String goUserAddPage(){        return "user_add";    }    /**     * 获取用户列表     * @param page 当前页码     * @param limit 每页显示条数     * @return     */    @ResponseBody    @RequestMapping("/list")    @RequiresPermissions("sys:user:list")    public ResultData getUserList(Integer page, Integer limit, String userName){        //PageHelper分页插件        PageHelper.startPage(page, limit);        List<User> userList = usi.queryList(userName);        PageInfo<User> p = new PageInfo<User>(userList);        return ResultData.ok().put("page", p);    }    /**     * 用户信息     */    @ResponseBody    @RequestMapping("/info")    @RequiresPermissions("sys:user:info")    public ResultData info(Long userId){        //执行查询        User userInfo = usi.queryObject(userId);        //获取用户所属的角色列表        List<Long> roleIdList = uarsi.queryRoleIdList(userId);        userInfo.setRoleIdList(roleIdList);        return ResultData.ok().put("userInfo", userInfo);    }    /**     * 保存用户     * @param user 用户实体     * @return     */    @ResponseBody    @RequestMapping("/save")    @RequiresPermissions("sys:user:save")    public ResultData saveUsers(@RequestBody User user){        //判断用户名称是否可用        User u = lsi.queryByUserName(user.getUsername());        if(u != null){            return ResultData.error("当前用户名称不能使用!");        }        usi.save(user);        return ResultData.ok();    }    /**     * 修改用户     */    @ResponseBody    @RequestMapping("/update")    @RequiresPermissions("sys:user:update")    public ResultData update(@RequestBody User user){        usi.update(user);        return ResultData.ok();    }    /**     * 删除用户     * @param userIdList 用户id数组     * @return     */    @ResponseBody    @RequestMapping("/delete")    @RequiresPermissions("sys:user:delete")    public ResultData deleteUsers(@RequestBody Long[] userIdList){        if(ArrayUtils.contains(userIdList, 1L)){            return ResultData.error("系统管理员不能删除");        }        if(ArrayUtils.contains(userIdList, getUserId())){            return ResultData.error("当前用户不能删除");        }        usi.deleteUser(userIdList);        return ResultData.ok();    }}

九、参考文档

    iview参考文档

    vue参考文档

    ztree参考文档

    shiro参考文档

十、获取该项目源代码

    A:微信扫描下方二维码,打赏一杯咖啡钱

    B:打赏的时候留下您的邮箱地址,二十四小时内通过邮箱发送给您

 

广告 广告

评论区