zoukankan      html  css  js  c++  java
  • SpringMVC集成Shiro、读取数据库操作权限

    1、Maven添加Shiro所需的jar包

            <dependency>
                <groupId>org.apache.shiro</groupId>
                <artifactId>shiro-core</artifactId>
                <version>${shiroversion}</version>
            </dependency>
            <dependency>
                <groupId>org.apache.shiro</groupId>
                <artifactId>shiro-ehcache</artifactId>
                <version>${shiroversion}</version>
            </dependency>
            <dependency>
                <groupId>org.apache.shiro</groupId>
                <artifactId>shiro-web</artifactId>
                <version>${shiroversion}</version>
            </dependency>
            <dependency>
                <groupId>org.apache.shiro</groupId>
                <artifactId>shiro-spring</artifactId>
                <version>${shiroversion}</version>
            </dependency>
            <dependency>
                <groupId>com.github.theborakompanioni</groupId>
                <artifactId>thymeleaf-extras-shiro</artifactId>
                <version>2.0.0</version>
            </dependency>

    ps:老夫用的1.4.0版本, ${shiroversion} 用 1.4.0替代就好

    2、添加 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:context="http://www.springframework.org/schema/context"
        xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
        xmlns:mvc="http://www.springframework.org/schema/mvc"
        xsi:schemaLocation="
            http://www.springframework.org/schema/beans 
            http://www.springframework.org/schema/beans/spring-beans-4.2.xsd        
            http://www.springframework.org/schema/context 
            http://www.springframework.org/schema/context/spring-context-4.2.xsd
            http://www.springframework.org/schema/tx 
            http://www.springframework.org/schema/tx/spring-tx-4.2.xsd
            http://www.springframework.org/schema/aop 
            http://www.springframework.org/schema/aop/spring-aop-4.2.xsd
            http://www.springframework.org/schema/mvc 
            http://www.springframework.org/schema/mvc/spring-mvc-4.2.xsd">
    
        <!-- 继承自AuthorizingRealm的自定义Realm,即指定Shiro验证用户登录的类为自定义的UserRealm.java -->  
        <bean id="userRealm" class="com.***.shiro.UserRealm"/>
    
        <!-- Shiro默认会使用Servlet容器的Session,可通过sessionMode属性来指定使用Shiro原生Session -->  
        <!-- 即<property name="sessionMode" value="native"/>,详细说明见官方文档 -->  
        <!-- 这里主要是设置自定义的单Realm应用,若有多个Realm,可使用'realms'属性代替 -->  
        <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">  
            <property name="realm" ref="userRealm"/>
        </bean>
    
        <!-- Shiro主过滤器本身功能十分强大,其强大之处就在于它支持任何基于URL路径表达式的、自定义的过滤器的执行 -->  
        <!-- Web应用中,Shiro可控制的Web请求必须经过Shiro主过滤器的拦截,Shiro对基于Spring的Web应用提供了完美的支持 -->  
        <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">  
            <!-- Shiro的核心安全接口,这个属性是必须的 -->  
            <property name="securityManager" ref="securityManager"/>  
            <!-- 要求登录时的链接(可根据项目的URL进行替换),非必须的属性,默认会自动寻找Web工程根目录下的"/login.html"页面 -->  
            <property name="loginUrl" value="/login.jsp"/>  
            <!-- 登录成功后要跳转的连接 -->  
            <property name="successUrl" value="/views/admin/common/master.jsp"/>
            <!-- 用户访问未对其授权的资源时,所显示的连接 -->  
            <!-- 若想更明显的测试此属性可以修改它的值,如unauthor.jsp,然后用[玄玉]登录后访问/admin/listUser.jsp就看见浏览器会显示unauthor.jsp -->  
            <!-- <property name="unauthorizedUrl" value="/no_permissions.jsp" />  --> 
            <!-- Shiro连接约束配置,即过滤链的定义 -->  
            <!-- 此处可配合我的这篇文章来理解各个过滤连的作用http://blog.csdn.net/jadyer/article/details/12172839 -->  
            <!-- 下面value值的第一个'/'代表的路径是相对于HttpServletRequest.getContextPath()的值来的 -->  
            <!-- anon:它对应的过滤器里面是空的,什么都没做,这里.do和.jsp后面的*表示参数,比方说login.jsp?main这种 -->  
            <!-- authc:该过滤器下的页面必须验证后才能访问,它是Shiro内置的一个拦截器org.apache.shiro.web.filter.authc.FormAuthenticationFilter -->  
            <property name="filterChainDefinitions">  
                <value>
                    <!-- anon表示此地址不需要任何权限即可访问 -->      
                    /static/** = anon  
                    /resources/** = anon 
                    /admin/login.do = anon
                    /** = authc
                </value>
            </property>
        </bean>
        <!-- Shiro生命周期处理器 -->
        <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>
        
    
        <!-- Shiro的注解配置放在spring-mvc中 -->
    
    </beans>

    3、web.xml里面添加 spring-shiro.xml 的引入

        <context-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>
                classpath:spring-base.xml,classpath:spring-mybatis.xml,classpath:spring-druid.xml,classpath:spring-shiro.xml
            </param-value>
        </context-param>

    4、在 spring-mvc.xml 里开启 shiro 的的注解

       <!-- 开启shiro注解-->
        <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>

    配置文件就到此结束了,下面自己创建一个 UserRealm;

    5、创建一个继承自AuthorizingRealm的自定义Realm,即指定Shiro验证用户登录的类为自定义的UserRealm.java

    package com.***.shiro;
    
    import java.util.ArrayList;
    import java.util.List;
    
    import javax.annotation.Resource;
    
    import org.apache.commons.lang.builder.ReflectionToStringBuilder;
    import org.apache.commons.lang.builder.ToStringStyle;
    import org.apache.shiro.SecurityUtils;
    import org.apache.shiro.authc.AuthenticationException;
    import org.apache.shiro.authc.AuthenticationInfo;
    import org.apache.shiro.authc.AuthenticationToken;
    import org.apache.shiro.authc.SimpleAuthenticationInfo;
    import org.apache.shiro.authc.UsernamePasswordToken;
    import org.apache.shiro.authz.AuthorizationException;
    import org.apache.shiro.authz.AuthorizationInfo;
    import org.apache.shiro.authz.SimpleAuthorizationInfo;
    import org.apache.shiro.realm.AuthorizingRealm;
    import org.apache.shiro.session.Session;
    import org.apache.shiro.subject.PrincipalCollection;
    import org.apache.shiro.subject.Subject;
    
    import com.**.entity.Admin;
    import com.**.entity.Permissions;
    import com.**.entity.Role;
    import com.**.entity.form.AdminForm;
    import com.**.entity.form.PermissionsForm;
    import com.**.entity.form.RoleForm;
    import com.**.service.IAdminService;
    import com.**.service.IPermissionsService;
    import com.**.service.IRoleService;
    
    public class UserRealm extends AuthorizingRealm {
    
        @Resource
        private IAdminService adminService;
        @Resource
        private IRoleService roleService;
        @Resource
        private IPermissionsService permissionsService;
    
        /**
         * 为当前登录的Subject授予角色和权限
         */
        @Override
        protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
            // 获取当前登录的用户名,等价于(String)principals.fromRealm(this.getName()).iterator().next()
            String username = (String) super.getAvailablePrincipal(principals);
            List<String> roleList = new ArrayList<String>();
            List<String> permissionList = new ArrayList<String>();
            // 从数据库中获取当前登录用户的详细信息
            AdminForm form = new AdminForm();
            form.setUserName(username);
            Admin admin = adminService.getList(form).get(0);
            if (null != admin) {
                // 实体类User中包含有用户角色的实体类信息
                if (null != admin.getRoleId()) {
                    // 获取当前登录用户的角色
                    RoleForm roleForm = new RoleForm();
                    roleForm.setId(admin.getRoleId());
                    
                    Role role = roleService.getList(roleForm).get(0);
                    roleList.add(role.getName());
                    
                    // 实体类Role中包含有角色权限的实体类信息
                    if (null != role.getPermissionsList()) {
                        String permissionsList[] = role.getPermissionsList().split(",");
                        // 获取权限
                        for (int i = 0; i < permissionsList.length; i++) {
                            PermissionsForm permissionsForm = new PermissionsForm();
                            permissionsForm.setId(Integer.parseInt(permissionsList[i]));
                            
                            Permissions permi = permissionsService.getList(permissionsForm).get(0);
                            permissionList.add(permi.getCode());
                        }
                    }
                }
            } else {
                throw new AuthorizationException();
            }
            // 为当前用户设置角色和权限
            SimpleAuthorizationInfo simpleAuthorInfo = new SimpleAuthorizationInfo();
            simpleAuthorInfo.addRoles(roleList);
            simpleAuthorInfo.addStringPermissions(permissionList);
            return simpleAuthorInfo;
        }
    
        /**
         * 验证当前登录的Subject
         * 
         * @see 经测试:本例中该方法的调用时机为LoginController.login()方法中执行Subject.login()时
         */
        @Override
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken)
                throws AuthenticationException {
            // 获取基于用户名和密码的令牌
            // 实际上这个authcToken是从AdminController里面currentUser.login(token)传过来的
            UsernamePasswordToken token = (UsernamePasswordToken) authcToken;
            System.err.println(
                    "验证当前Subject时获取到token为" + ReflectionToStringBuilder.toString(token, ToStringStyle.MULTI_LINE_STYLE));
            AdminForm form = new AdminForm();
            form.setUserName(token.getUsername());
            Admin admin = adminService.getList(form).get(0);
            if (null != admin) {
                AuthenticationInfo authcInfo = new SimpleAuthenticationInfo(admin.getUserName(), admin.getPassword(),
                        admin.getId().toString());
                this.setSession("currentUser", admin);
                return authcInfo;
            } else {
                return null;
            }
        }
    
        /**
         * 将一些数据放到ShiroSession中,以便于其它地方使用
         * 
         * @see 比如Controller,使用时直接用HttpSession.getAttribute(key)就可以取到
         */
        private void setSession(Object key, Object value) {
            Subject currentUser = SecurityUtils.getSubject();
            if (null != currentUser) {
                Session session = currentUser.getSession();
                System.out.println("Session默认超时时间为[" + session.getTimeout() + "]毫秒");
                if (null != session) {
                    session.setAttribute(key, value);
                }
            }
        }
    }

    数据库、实体、Dao配置省略。。。

    附:表片段

    6、在登录方法中,登录成功后将用户添加到 shiro 的 Subject 中

    UsernamePasswordToken token = new UsernamePasswordToken(admin.getUserName(), admin.getPassword());
                
    Subject currentUser = SecurityUtils.getSubject();
    currentUser.login(token);

    7、在需要访问权限的方法上添加 @RequiresPermissions() 注解

       @RequestMapping("/permissionsList")
        @RequiresPermissions("permissionsList")
        public ModelAndView permissionsList(HttpServletRequest request) {
            ModelAndView mv = new ModelAndView();
            
            PermissionsForm form = new PermissionsForm();
            if (!StringUtils.isEmpty(request.getParameter("id")))
                form.setId(Integer.parseInt(request.getParameter("id")));
            if (!StringUtils.isEmpty(request.getParameter("name")))
                form.setName(request.getParameter("name"));
            if (!StringUtils.isEmpty(request.getParameter("group")))
                form.setGroup(request.getParameter("group"));
            
            List<Permissions> menuList = permissionsService.getList(form);
            
            mv.addObject("menuList", menuList);
            mv.addObject("id", request.getParameter("id"));
            mv.addObject("name", request.getParameter("name"));
            mv.addObject("group", request.getParameter("group"));
            mv.setViewName("views/admin/system_manage/permissions_list");
            return mv;
        }
    @RequiresPermissions("permissionsList") : 表示拥有 permissionsList 权限方可访问该方法


    附加:
      实际使用访问到不具有权限的地址时会报错 org.apache.shiro.authz.UnauthorizedException 或者 org.apache.shiro.authz.UnauthenticatedException

      此时需要在 spring-mvc.xml 里添加 错误跳转未授权页面

        <!-- shiro异常跳转 -->
        <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">  
            <property name="exceptionMappings">  
                <props>  
                    <prop key="org.apache.shiro.authz.UnauthorizedException">no_permissions</prop>  
                    <prop key="org.apache.shiro.authz.UnauthenticatedException">no_permissions</prop>  
                </props>  
            </property>  
        </bean> 
    no_permissions 为 ModelAndView。 
    完结。。。
  • 相关阅读:
    AtCoder Beginner Contest 167
    AtCoder Beginner Contest 166
    AtCoder Beginner Contest 165
    AtCoder Beginner Contest 164
    AtCoder Beginner Contest 163
    AtCoder Beginner Contest 162
    AtCoder Beginner Contest 161
    AtCoder Beginner Contest 160
    AtCoder Beginner Contest 159
    自定义Mybatis自动生成代码规则
  • 原文地址:https://www.cnblogs.com/linnuo/p/7999046.html
Copyright © 2011-2022 走看看