shiro权限框架

时间:2023-03-09 04:52:50
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 配置,见上...