分享知识-快乐自己:Shrio 案例Demo概述

Shiro 权限认证核心:

POM:文件:

<!--shiro-all-->
<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-all</artifactId>
    <version>1.2.3</version>
</dependency>
<!-- 添加shrio-web支持 -->
<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-web</artifactId>
    <version>1.2.4</version>
</dependency>
<!-- 添加shrio-spring支持 -->
<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-spring</artifactId>
    <version>1.2.4</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.shiro/shiro-ehcache -->
<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-ehcache</artifactId>
    <version>1.4.0</version>
</dependency>

WEB.XML:

<!--01.配置 Shiro 的 ShiroFilter-->
<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>

spring-shiro.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"
    xmlns:p="http://www.springframework.org/schema/p"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:jee="http://www.springframework.org/schema/jee"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="    
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd  
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-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/jee http://www.springframework.org/schema/jee/spring-jee-4.0.xsd  
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd">

    <!-- 自定义Realm -->
    <bean id="myRealm"
        class="com.dsj.gdbd.controller.shiro.realm.MyRealm">
        <property name="credentialsMatcher">
            <bean
                class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
                <property name="hashAlgorithmName" value="MD5"></property>
                <property name="hashIterations" value="1"></property>
            </bean>
        </property>
    </bean>

    <bean id="securityManager"
        class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
        <!-- 注入realm -->
        <property name="realm" ref="myRealm" />
    </bean>

    <!-- 开启Shiro注解 -->
    <bean
        class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
        <property name="securityManager" ref="securityManager" />
    </bean>

    <!-- 重写Shiro登录过滤器 -->
    <bean id="loginAgainFilter"
        class="com.dsj.gdbd.controller.shiro.filter.MyFormAuthenticationFilter"></bean>
    <bean id="shiroFilter"
        class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
        <!-- Shiro的核心安全接口,这个属性是必须的 -->
        <property name="securityManager" ref="securityManager" />

        <!-- 身份认证失败,则跳转到登录页面的配置(这里的路径与 form 表单路径一致,并且是 POST 请求) -->
        <property name="loginUrl" value="/login/to_login" />

        <!-- 权限认证失败,则跳转到指定页面 -->
        <property name="unauthorizedUrl"
            value="/login/to_unauthorized" />

        <!-- 权限认证成功,则跳转到指定页面 -->
        <property name="successUrl" value="/home/to_index" />

        <property name="filters">
            <map>
                <entry key="mauthc" value-ref="loginAgainFilter" />
                <entry key="logout">
                    <!-- 退出之后的重定向地址 -->
                    <bean class="org.apache.shiro.web.filter.authc.LogoutFilter">
                        <property name="redirectUrl" value="/login/to_login" />
                    </bean>
                </entry>
            </map>
        </property>

        <property name="filterChainDefinitions">
            <value>

                <!-- anon 表示可以匿名使用。 -->
                /static/**=anon

                /login/to_login=mauthc
                /login/logout=logout
                /login/**=anon
                <!-- authc表示需要认证(登录)才能使用 -->
                /** = authc
            </value>
        </property>
    </bean>

</beans>

重写Shiro登录过滤器 :

package com.dsj.gdbd.controller.shiro.filter;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;

public class MyFormAuthenticationFilter extends FormAuthenticationFilter {
    //重写登录成功
    @Override
    protected boolean onLoginSuccess(AuthenticationToken token, Subject subject, ServletRequest request,
            ServletResponse response) throws Exception {
        //开启授权
        subject.hasRole("*");
        
        return super.onLoginSuccess(token, subject, request, response);
    }
}

MyRealm.java  验证授权:

package com.dsj.gdbd.controller.shiro.realm;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UnknownAccountException;
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 com.dsj.gdbd.pojo.MenuFunction;
import com.dsj.gdbd.pojo.RoleInfo;
import com.dsj.gdbd.pojo.UserInfo;
import com.dsj.gdbd.service.MenuFunctionService;
import com.dsj.gdbd.service.RoleInfoService;
import com.dsj.gdbd.service.UserInfoService;
import com.dsj.gdbd.utils.enums.DeleteStatusEnum;

public class MyRealm extends AuthorizingRealm {
    @Autowired
    private UserInfoService userInfoService;
    @Autowired
    private RoleInfoService roleInfoService;
    @Autowired
    private MenuFunctionService menuFunctionService;
    private final Logger LOGGER = LoggerFactory.getLogger(MyRealm.class);

    @SuppressWarnings("unchecked")
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {

        /**
         *
         * 流程 1.根据用户user->2.获取角色id->3.根据角色id获取权限
         */
        // 01、获取用户登陆ing
        String realName = (String) principals.getPrimaryPrincipal();
        LOGGER.info("realName{}", realName);
        // 02、设置查询条件
        UserInfo info = new UserInfo();
        info.setRealName(realName);
        info.setDelFlag(DeleteStatusEnum.NDEL.getValue());
        // 03、查询对象信息
        UserInfo userInfo = userInfoService.getInfo(info);
        LOGGER.info("admin.id{}", userInfo.getId());
        LOGGER.info("admin.name{}", userInfo.getUserName());
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        // 04、获取用户下的所有角色
        List<RoleInfo> rolelist = roleInfoService.getRoles(userInfo.getId());
        // 获取所有角色的 Id
        List<Long> rolesIds = new ArrayList<Long>();
        for (RoleInfo item : rolelist) {
            rolesIds.add(item.getId());
        }
        // 05、角色下所拥有的所有权限
        List<MenuFunction> listMenus = menuFunctionService.getListMenus(rolesIds);
        // 获取访问的权限
        List<String> patterns = new ArrayList<String>();
        for (MenuFunction item : listMenus) {
            patterns.add(item.getPattern());
        }
        // 06、设置绑定 分类级别关系
        List<MenuFunction> menuFunction = menuFunction(listMenus);
        // 07、去掉空的权限
        List<MenuFunction> notNullMenus = notNull(menuFunction);
        // 08、权限菜单集合保存在Session 回话中
        SecurityUtils.getSubject().getSession().setAttribute("menus", notNullMenus);
        // 09、当前用户所拥有的所有权限保存在 session 会话中进行对比
        SecurityUtils.getSubject().getSession().setAttribute("menusPatterns", patterns);
        // 10、当前登录的用户信息
        SecurityUtils.getSubject().getSession().setAttribute("sessionUser", userInfo);
        // 11、将用户拥有的权限保存在 shiro中 用于后期页面的权限验证
        authorizationInfo.addStringPermissions(
                (List<String>) SecurityUtils.getSubject().getSession().getAttribute("menusPatterns"));
        return authorizationInfo;
    }

    /***
     * 认证方法 验证账号密码
     */
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) {
        System.out.println("进行验证了");
        // 01、获取登录用户名
        String realName = (String) authenticationToken.getPrincipal();
        // 02、设置条件
        UserInfo info = new UserInfo();
        info.setRealName(realName);
        info.setDelFlag(DeleteStatusEnum.NDEL.getValue());
        // 03、查询对象信息
        UserInfo userInfo = userInfoService.getInfo(info);
        if (userInfo == null) {
            throw new UnknownAccountException();
        }
        // 最后的比对需要交给安全管理器
        // 三个参数进行初步的简单认证信息对象的包装(验证密码)
        SimpleAuthenticationInfo authcInfo = new SimpleAuthenticationInfo(userInfo.getRealName(), userInfo.getUserPwd(),
                this.getName());
        return authcInfo;
    }

    /***
     * 执行遍历
     * 
     * @param menus
     *            所有权限列表集合
     * @param list
     *            指定角色查询到的 权限Id
     * @return
     */
    @SuppressWarnings("unused")
    private List<MenuFunction> menuFunction(List<MenuFunction> menus) {
        // 中转集合
        List<MenuFunction> functions = null;
        try {
            functions = new ArrayList<MenuFunction>();
            // 循环遍历菜单层级关系
            // 循环遍历
            for (MenuFunction item : menus) {
                // 获取pid
                long pid = item.getPid();
                if (pid == 0) {
                    // 遍历一级分类
                    functions.add(item);
                } else {
                    for (MenuFunction innerCate : menus) {
                        /***
                         * 外层循环 pid 没有的等于0 的话 获取当前对象的 id 作为一级
                         */
                        Long id = innerCate.getId();

                        if (id == pid) {
                            innerCate.getChildren().add(item);
                            break;
                        }
                    }
                }
            }

        } catch (Exception e) {
            LOGGER.error("循环遍历层级关系失败!!!" + e);
        }
        return functions;
    }

    /***
     * 去掉空的权限
     * 
     * @param list
     * @return
     */
    private List<MenuFunction> notNull(List<MenuFunction> list) {
        List<MenuFunction> menusList = null;
        try {
            // 去掉空的权限
            menusList = new ArrayList<MenuFunction>();
            for (int i = 0; i < list.size(); i++) {
                if (list.get(i).getChildren().size() != 0) {
                    menusList.add(list.get(i));
                    notNull(list.get(i).getChildren());
                }
            }
        } catch (Exception e) {
            LOGGER.error("去除空的权限时意外出错!!!" + e);
        }
        return menusList;
    }
}

Controller 关键代码:

package com.dsj.gdbd.controller.login;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
/***
 * 登陆
 * @author asus
 *
 */
@Controller
@RequestMapping("login")
public class LoginController {
 
    /***
     * 跳转登录页
     * @return
     */
    @RequestMapping("to_login")
    public String login() {
        
        return "login/login";
    }
}

 

package com.dsj.gdbd.controller.home;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
@RequestMapping("home")
public class HomeController {
 
    /***
     * 跳转主页面
     * @return
     */
    @RequestMapping("to_index")
    public String login() {
        
        return "home/welcome";
    }
}

login.jsp:登录页:(重点关注 form 表单 与 异常处理 )

<%@ page contentType="text/html;charset=UTF-8"%>
<%@include file="/WEB-INF/jsp/common/taglibs.jspf"%>
<html lang="en">
<head>
<link rel="stylesheet" href="${ctx}/static/front/css/login/style.css">
<link rel="stylesheet"
    href="${ctx}/static/front/bootstrap/3.3.7/css/bootstrap.min.css">
<script src="${ctx}/static/front/js/jquery.min.js"></script>
<script src="${ctx}/static/front/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<script src='${ctx}/static/front/js/style.js'></script>
<script type="text/javascript">
    var _ctx = '${ctx}';
</script>
<title>登录</title>
</head>
<style>
</style>
<body>
    <!-- <div class="bj"> -->
    <header>
        <img src="${ctx}/static/front/images/login/logo.png" alt="">
    </header>
    <!-- </div> -->

    <div class="city">
        <img src="${ctx}/static/front/images/login/4.png" alt="">
        <div class="denglu">
            <div class="titBian">
                <span class="tit">用户登录</span>

            </div>
            <form id="loginForm" action="${ctx }/login/to_login" method="post">
                <div class="fengexian"></div>
                <div class=" alert-danger dengLuTiShi" id="errorDiv">
                    <span class="dengLuTiShiTu glyphicon glyphicon-minus-sign"></span><span
                        id="error" class="cuo">${errormsg }</span>
                </div>

                <div class="input-group name">
                    <span class="input-group-addon tx1" id="basic-addon1"><img
                        id="tx" class="tupian"
                        src="${ctx}/static/front/images/login/tuyiyi-com-0.png" alt=""></span>
                    <input type="text" id="phone" onclick="phone2()" name="username"
                        class="form-control" autocomplete="off" placeholder="请输入手机号或账号"
                        aria-describedby="basic-addon1"> <span
                        class="input-group-addon cha1" id="cha" onclick="qingkong()">X</span>
                </div>
                <div class="input-group password">
                    <span class="input-group-addon tx1" id="basic-addon2"><img
                        src="${ctx}/static/front/images/login/7.png" id="mm"
                        class="tupian" alt=""></span> <input type="password" id="mima"
                        name="password" class="form-control" onclick="mma()"
                        autocomplete="off" placeholder="请输入密码"
                        aria-describedby="basic-addon1">
                </div>
                <span class="wangjimima" onclick="wangji()">忘记密码</span>
                <button id="login_btn" type="button" class="btn btn-primary btnDL">登录</button>
            </form>
            <%
                //shiro 获取异常,判断异常类型
                Object errorClass = request.getAttribute("shiroLoginFailure");
                if ("org.apache.shiro.authc.IncorrectCredentialsException".equals(errorClass)) {

                    request.setAttribute("errormsg", "用户名或密码错误");
                }
                if ("org.apache.shiro.authc.UnknownAccountException".equals(errorClass)) {
                    request.setAttribute("errormsg", "用户不存在或已禁用");
                }
                if ("com.dsj.data.shiro.filter.VerifyCodeException".equals(errorClass)) {
                    request.setAttribute("errormsg", "验证码不正确");
                }
            %>

        </div>

    </div>
    <div class="yun">
        <div class="kuanCont">
            <a class="kuan">&nbsp;&nbsp;联系我们xxxxx&nbsp;&nbsp;</a> <a
                class="kuan kuanLast">&nbsp;&nbsp;北京xxxxx技术服务有限公司&nbsp;&nbsp; </a>
        </div>
    </div>
    <script type="text/javascript">
        $(function() {
            $("#login_btn").off().on("click", function() {
                $("#loginForm").submit();
            });
            if ('${errormsg }' != '') {
                var errorDiv = document.getElementById('errorDiv');
                $("#error").html("${errormsg }");
                errorDiv.style.visibility = 'visible';
            }

        })

        $(document).keydown(function(event) {
            if (event.keyCode == 13) { //绑定回车 
                $('#login_btn').click();
            }
        });
    </script>
    <script src="${ctx }/static/back/login/login.js"></script>
</body>
</html>

其他 相关 Shiro 权限 Demo:案例Demo并不是很完整,你只需要拿走里面你需要的配置就好。

下载地址一  下载地址二

 

posted @ 2018-12-16 14:14  GDBD  阅读(338)  评论(0编辑  收藏  举报