shiro权限框架

权限的组成部分:用户 资源 角色 权限

数据库关系表设计是根据自己项目需求设计的

account表
role表(id,rolename)
account_role(id,aid,rid)
permission(id,pername)
role_permission(id,rid,pid)

 没有设置用户和权限的关系,我们可以认为用户的权限是通过角色来决定的

1.导入jar包

shiro-all-1.2.1.jar

2.配置web.xml

    <!-- 权限过滤器-->
  <filter>
      <filter-name>shiroFilter</filter-name>
    <!-- 委托给spring,所以还要在spring中配置 -->
      <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
  </filter>
  <filter-mapping>
      <filter-name>shiroFilter</filter-name>
      <url-pattern>/*</url-pattern>
  </filter-mapping>

3.新建applicationContext-shiro.xml 

因为在web.xml中有配置spring容器,它会读取applicationContext开头的配置文件
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext*.xml</param-value>
</context-param>

<?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.xsd"
>
    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
        <property name="cacheManager" ref="cacheManager"/>
        <!-- 权限框架的操作类 myShiroRealm,可以service中新建这个类-->
        <property name="realm" ref="myShiroRealm"/>
    </bean>
    
    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
        <property name="securityManager" ref="securityManager"/>
        
        <!-- 以下是跟登录权限有关的配置 -->
        
        <!-- 配置登录的url -->
        <property name="loginUrl" value="/"/>
        <!-- 登录成功的url -->
        <property name="successUrl" value="/book/1"/>
        <!-- 没有权限的url -->
        <property name="unauthorizedUrl" value="/403"/>
        
        <property name="filterChainDefinitions">
            <value>
            
                <!-- 静态资源不用认证 要放在/** = authc之前,因为当所有的都要认证的时候再写它就没用了-->
                /static/** = anon
                <!-- 角色配置,没有管理员这个角色的账户是不能访问/book/**里面的内容的 -->
                /book/** = roles[管理员]
                <!-- 权限配置,不要只在界面上用标签配置 没有book:add的权限的账户是不能访问/book/add的
                    但是如果没有权限你还是要访问的话,就要到上面的<property name="unauthorizedUrl" value="/403"/>
                    里面了,自定义一个403页面,这里举出一个例子,可以在mvc-servlet配置静态资源
                    <mvc:view-controller path="/403" view-name="403"/>-->
                /book/add = perms[book:add]
                
                <!-- (根目录及其子目录)所有的资源都是需要认证的 这个时候以前mvc-servlet里面的拦截器就不用写了-->
                /** = authc
            </value>
        </property>
    </bean>
    
    <bean id="cacheManager"
        class="org.apache.shiro.cache.MemoryConstrainedCacheManager" />
    <bean id="lifecycleBeanPostProcessor"
        class="org.apache.shiro.spring.LifecycleBeanPostProcessor" />


</beans>

 

举例

package com.kaishengit.service;

import javax.inject.Inject;
import javax.inject.Named;

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.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;

import com.kaishengit.pojo.Admin;

// 需要继承自AuthorizingRealm并实现它的方法
@Named
public class MyShiroRealm extends AuthorizingRealm{

    @Inject
    private AdminService adminService;
    
    
    /**
     * 权限认证方法
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection pCollection) {
        //获取当前登录的用户名
        String loginName = (String) pCollection.fromRealm(getName()).iterator().next();
        
        Admin admin = adminService.findByName(loginName);
        if(admin != null) {
            SimpleAuthorizationInfo sInfo = new SimpleAuthorizationInfo();
            //1. 获取当前用户拥有的所有角色
            sInfo.setRoles(adminService.getRoles(admin));
            /* adminService中的该方法
                public Set<String> getRoles(Admin admin) {
                    List<Role> roles = roleDao.findByAdminId(admin.getId());
                    因为是要返回的set集合
                    Set<String> roleNames = new HashSet<String>();
                    
                    for(Role r : roles) {
                        roleNames.add(r.getRolename());
                    }
                    return roleNames;
                }*/
            
            //2. 获取当前用户拥有的所有权限
            // 还有一个方法,跟下面的不同的是set第二次会覆盖,add表示添加
            //sInfo.addStringPermissions(adminService.getPermissions(admin));
            sInfo.setStringPermissions(adminService.getPermissions(admin));
            
            /* adminService中的该方法
                public Set<String> getPermissions(Admin admin) {
                    一个账户可能有多个角色
                    List<Role> roles = roleDao.findByAdminId(admin.getId());
                    
                    Set<String> permissions = new HashSet<String>();
                    
                    for(Role role : roles) {
                        一个角色可能有多个权限
                        List<Permission> perList = permissionDao.findByRoleId(role.getId());
                        for(Permission p : perList) {
                            装入set集合
                            permissions.add(p.getPername());
                        }
                    }
                    return permissions;
                }
                */
            return sInfo;
        }
        
        
        return null;
    }

    /**
     * 登录认证方法
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(
            AuthenticationToken auToken) throws AuthenticationException {
        // 强制转换
        UsernamePasswordToken token = (UsernamePasswordToken) auToken;
        // 通过名字查询,用的是token.getUsername,那这个名字是从哪里放进来的呢,是在controller中new出来
        //    的token,然后传进去的账户信息,然后在这里get
        Admin admin = adminService.findByName(token.getUsername());
        
        if(admin != null) {
            // 如果查询得到一个admin就算登录成功 ,因为下面的构造函数会传入账户和密码,然后自动检测 
            return new SimpleAuthenticationInfo(admin.getName(),admin.getPassword(),getName());
        }
        return null;
    }

}

 

@Controller
public class AdminController {

    @Inject
    private AdminService adminService;
    
    @RequestMapping(value="/",method=RequestMethod.POST)
    public String login(Admin admin,HttpSession session,RedirectAttributes redirectAttributes) {
        
        try {
            /* 在这里new出来 UsernamePasswordToken,传入账户信息
                当在这里调用login的时候就会自动调用MyShiroRealm中登录认证的那个方法
                
                这个方法是不会抛出异常的,但是我们还是要try catch一下,因为这个方法不能做判断
                    所以当来到catch的时候就说明登录失败了*/
            SecurityUtils.getSubject().login(new UsernamePasswordToken(admin.getName(), admin.getPassword()));
            return "redirect:/book/1";
        } catch (AuthenticationException e) {
            redirectAttributes.addFlashAttribute("message", "账号或密码错误");
            return "redirect:/";
        }
        
        
        
        /*
        这是以前的方法
        Admin currAdmin = adminService.login(admin.getName(),admin.getPassword());
        if(currAdmin == null) {
            redirectAttributes.addFlashAttribute("message", "账号或密码错误");
            return "redirect:/";
        } else {
            session.setAttribute("curr_admin", currAdmin);
            return "redirect:/book";
        }*/
    }
    
    
    
}

 

 jsp中对应的标签 
 首先导入标签 

<%@ taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>

<!-- 该账户有的角色中存在权限 book:add权限的话就能添加书籍-->
<shiro:hasPermission name="book:add">
    <a href="/book/add" class="btn btn-success">添加书籍</a>
</shiro:hasPermission>

<table class="table">
    <thead>
        <tr>
            <th>书籍编号</th>
            <th>书籍名称</th>
            <th>作者</th>
            <th>出版社</th>
            <th>总数量</th>
            <th>当前数量</th>
            <th>#</th>
        </tr>
    </thead>
    <tbody>
        
        <c:forEach items="${bookList }" var="book">
            <tr>
                <td>${book.code }</td>
                <td>${book.name }</td>
                <td>${book.author }</td>
                <td>${book.publish }</td>
                <td>${book.total}</td>
                <td>${book.nowcount }</td>
                <td>
                    <shiro:hasPermission name="book:edit">
                        <a href="/book/edit/${book.id }">修改</a>
                    </shiro:hasPermission>
                    <shiro:hasPermission name="book:remove">
                        <a href="/book/del/${book.id }">删除</a>
                    </shiro:hasPermission>
                </td>
            </tr>
        </c:forEach>
    </tbody>
</table>

 

这个标签只是在界面上控制不让它显示,但是如果在url上直接进入还是控制不住的,所以要在
applicationContext-shiro.xml 配置,见上...

 

posted on 2015-02-24 22:13  itliucheng  阅读(798)  评论(0编辑  收藏  举报