shiro 管理权限

参考了http://blog.csdn.net/frankcheng5143/article/details/50836619这篇文章。感谢GW_Cheng大神的启发。 
参考shiro官方文档将shiro和spring集成。spring的基本配置默认都懂,不说了。项目用maven管理,这个也不细说了,大不了启动的时候看报错缺什么文件写什么依赖吧- -哈哈。后面我会做一个完整项目放在github上。

1、首先确定自己的权限方案是:为用户分配角色,角色拥有某种权限。而且是用数据库存储用户信息,包括用户资料、角色、权限信息。因此要建立5张表。分别是: 
用户表,存储用户的相关信息 
角色表,存储角色的相关信息 
权限表,存储权限的相关信息 
用户角色表,存储用户和角色的对应关系 一对多 
角色权限表,存储角色和权限的对应关系 一对多

详情看大神的博客吧。

2、在web.xml中定义shiro的过滤器

    
    <filter>
        <filter-name>shiroFilterfilter-name>
        <filter-class>org.springframework.web.filter.DelegatingFilterProxyfilter-class>
        <init-param>
            <param-name>targetFilterLifecycleparam-name>
            <param-value>trueparam-value>
        init-param>
    filter>
    
    <filter-mapping>
        <filter-name>shiroFilterfilter-name>
        <url-pattern>/*url-pattern>
    filter-mapping>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

2、spring-shiro.xml 
这个文件会 import到spring的核心配置文件中。有人叫applicationcontext.xml,有人叫spring-core.xml……主要看自己习惯吧。反正web.xml里面写对了就能识别了。spring-core.xml里面记得配一个数据库连接池,druid、c3p0皆可。


<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.1.xsd">

    
    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
        
        <property name="securityManager" ref="securityManager" />
        
        <property name="loginUrl" value="/login.jsp" />
        
        
        
        

        <property name="filterChainDefinitions">
            
            <value>
                /admin/**=authc
            value>
        property>

    bean>


    <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor">bean>
    
    <bean id="credentialsMatcher" class="org.apache.shiro.authc.credential.Md5CredentialsMatcher">bean>
    
    <bean id="shiroCacheManager" class="org.apache.shiro.cache.MemoryConstrainedCacheManager">bean>

    
    <bean id="jdbcRealm" class="org.apache.shiro.realm.jdbc.JdbcRealm">
        <property name="credentialsMatcher" ref="credentialsMatcher">property>
        <property name="permissionsLookupEnabled" value="true">property>
        <property name="dataSource" ref="dataSource">property>
        <property name="authenticationQuery"
            value="SELECT password FROM sec_user WHERE user_name = ?">property>
        <property name="userRolesQuery"
            value="SELECT role_name from sec_user_role left join sec_role using(role_id) left join sec_user using(user_id) WHERE user_name = ?">property>
        <property name="permissionsQuery"
            value="SELECT permission_name FROM sec_role_permission left join sec_role using(role_id) left join sec_permission using(permission_id) WHERE role_name = ?">property>
    bean>

    
    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
        <property name="realm" ref="jdbcRealm">property>
        <property name="cacheManager" ref="shiroCacheManager">property>
    bean>

    

beans>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56

3、springmvc配置,让springmvc控制权限认证后的跳转。


<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:context="http://www.springframework.org/schema/context"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans-3.1.xsd 
        http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context-3.1.xsd 
        http://www.springframework.org/schema/mvc 
        http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd ">

    
    <import resource="classpath:spring/spring-shiro.xml" />

    
    <context:component-scan base-package="com.test.controller">
        <context:include-filter type="annotation"
            expression="org.springframework.stereotype.Controller" />
    context:component-scan>

    
    <mvc:view-controller path="/" view-name="index" />

    
    <mvc:annotation-driven />

    
    <mvc:resources location="/assets/" mapping="/assets/**">mvc:resources>

    
    <bean
        class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/views/" />
        <property name="suffix" value=".jsp" />
    bean>

    
    <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>

    
    <bean
        class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
        <property name="exceptionMappings">
            <props>
                
                <prop key="org.apache.shiro.authz.UnauthorizedException">
                    
                    /error/unauthorized
                prop>
                
                <prop key="org.apache.shiro.authz.UnauthenticatedException">
                    
                    /error/unauthorized
                prop>
            props>
        property>
    bean>
beans>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70

4、shiro的一些功能会用到缓存(比如remenber me),先配置好。(这一块我没有详细理解) 
spring-cache.xml


<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:cache="http://www.springframework.org/schema/cache"
       xsi:schemaLocation="
        http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
        http://www.springframework.org/schema/cache
        http://www.springframework.org/schema/cache/spring-cache-3.1.xsd">


    <cache:annotation-driven cache-manager="cacheManager"/>

    <bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager" p:cacheManager-ref="ehcache"/>

    <bean id="ehcache"
          class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"
          p:configLocation="classpath:ehcache.xml"/>
beans>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

ehcache.xml


<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:noNamespaceSchemaLocation="http://www.ehcache.org/ehcache.xsd">

    <diskStore path="java.io.tmpdir/ehcache" />

    
    <defaultCache 
        maxElementsInMemory="1000" 
        eternal="false"
        timeToIdleSeconds="120" 
        timeToLiveSeconds="120" 
        overflowToDisk="false" />

    
    
    <cache name="userIsExists" 
        maxElementsInMemory="1000" 
        eternal="false"
        timeToIdleSeconds="120" 
        timeToLiveSeconds="120" 
        overflowToDisk="false"
        memoryStoreEvictionPolicy="LRU" />
    
    <cache name="getUserById" 
        maxElementsInMemory="1000" 
        eternal="false"
        timeToIdleSeconds="120" 
        timeToLiveSeconds="120" 
        overflowToDisk="false"
        memoryStoreEvictionPolicy="LRU" />

ehcache>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44

配置部分到此结束,暂时没有用到MyBatis。 
5、下面分析代码。主要是2个controller。 
我们在shiro的配置里面使用默认的jdbcRealm,所以这个也不用自己写了,直接用。 
登录的controller:

  UsernamePasswordToken token = new UsernamePasswordToken(user.getUsername(), user.getPassword());
        token.setRememberMe(true);
        Subject subject = SecurityUtils.getSubject();
        try {
            subject.login(token);
            if (subject.isAuthenticated()) {
                request.getSession().setAttribute("user",user);
                SavedRequest savedRequest = WebUtils.getSavedRequest(request);
                // 获取保存的URL
                if (savedRequest == null || savedRequest.getRequestUrl() == null) {
                    return "admin/home";
                } else {
                    return "forward:" + savedRequest.getRequestUrl();
                }
            } else {
                return "login";
            }
        } catch (IncorrectCredentialsException e) {
            msg = "登录密码错误. Password for account " + token.getPrincipal() + " was incorrect.";
            model.addAttribute("message", msg);
            System.out.println(msg);
        }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

在其他的Controller中,使用注解来做权限控制访问。

    // 只用同时具有user:view和user:create权限才能访问
    @RequiresPermissions(value = { "user:view", "user:create" }, logical = Logical.AND)
    @RequestMapping(value = "/admin/auth")
    public String adminWithAuth() {
        return "admin/withauth";
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

当没有权限就去访问时,会抛出对应的异常。

6、学习心得体会。 
1)文中查到一个用户之后,怎么知道他的权限呢?其过程是这样的:

id="jdbcRealm" class="org.apache.shiro.realm.jdbc.JdbcRealm">
        <property name="credentialsMatcher" ref="credentialsMatcher">property>
        <property name="permissionsLookupEnabled" value="true">property>
        <property name="dataSource" ref="dataSource">property>
        <property name="authenticationQuery"
                  value="SELECT password FROM sec_user WHERE user_name = ?">property>
        <property name="userRolesQuery"
                  value="SELECT role_name from sec_user_role left join sec_role using(role_id) left join sec_user using(user_id) WHERE user_name = ?">property>
        <property name="permissionsQuery"
                  value="SELECT permission_name FROM sec_role_permission left join sec_role using(role_id) left join sec_permission using(permission_id) WHERE role_name = ?">property>
    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

jdbcrealm里面写了一些查询角色和授权的sql语句,在使用subject.login(token);登录之后就会自动根据数据库查到的信息,为用户分配角色和授权。 
角色和权限实现的方式有很多种,文中只是方案之一。希望自己在未来深入了解之后,也能写出属于自己的解决方案吧。 
2)在实现自定义的realm时(这个是后续学习的关键),可以使用mybatis来查数据库中的数据,自己做权限的分配。 
3)密码如果使用了salt混淆来生成md5,jdbcRealm里面的相应配置我还没有弄清除具体怎么操作。如果saltStyle配了Column属性,sql数据库里user表似乎就要多加一列salt了。或者用external属性,将username作为salt。时间有限,先直接用没有混淆的MD5加密密码吧。

版权声明:本文为博主原创文章,未经博主允许不得转载。 http://blog.csdn.net/kaka0509/article/details/70196884

你可能感兴趣的:(java)