授权即访问控制,它将判断用户在应用程序中对资源是否拥有相应的访问权限。如,判断一个用户有查看页面的权限,编辑数据的权限,拥有某一按钮的权限,以及是否拥有打印的权限等等。
认证通过后接受 Shiro授权检查,授权验证时,需要判断当前角色是否拥有该权限。只有授权通过,才可以访问受保护 URL 对应的资源,否则跳转到“未经授权页面”。
首先来结合一个实例来说明:
上篇博客(深入浅出学Shiro(一)--登录认证)已经讲解了配置,下面我们直接来看代码实现
shiro认证成功后,跳转到main.jsp页面
Main.jsp页面内容:
<body>
<ul>
<li>
<h2>
<a target="_self" href="user.do?myjsp">访问myjsp页面</a>
</h2>
</li>
<li>
<h2>
<a target="_self" href="user.do?notmyjsp">访问notmyjsp页面(无权访问)</a>
</h2>
</li>
<li>
<h2>
<a target="_self" href="user.do?visitAdminPage">访问admin页面</a>
</h2>
</li>
<li>
<h2>
<a target="_self" href="user.do?visitByAnnotation">通过注解访问页面(无权访问)</a>
</h2>
</li>
</ul>
</body>
当点击页面某个链接时,跳转到相应的controller
@Controller
@RequestMapping(value="user")
public class UserController {
/**
* 访问myjsp页面,有权限
* @return
*/
@RequestMapping(params = "myjsp")
public String home() {
/*通过SecurityUtils工具类,获取当前的用户*/
Subject currentUser = SecurityUtils.getSubject();
// 回调 doGetAuthorizationInfo,进行授权验证
if(currentUser.isPermitted("user.do?myjsp")){
return "my";
}else{
return "error/noperms";
}
}
当程序执行到currentUser.isPermitted方法时,调用到publicclass DelegatingSubject implements Subject类的isPermitted方法。
附源码:
public boolean isPermitted(String permission) {
return hasPrincipals() && securityManager.isPermitted(getPrincipals(), permission);
}
通过上篇博客我们知道,这时SecurityManager会委托给Realm,故接下来执行我们自定义的Realm:
@Service("monitorRealm")
public class MonitorRealm extends AuthorizingRealm {
//获取授权信息
@Override
protected AuthorizationInfo doGetAuthorizationInfo(
PrincipalCollection principals) {
/* 这里编写授权代码 */
Set<String> roleNames = new HashSet<String>();
Set<String> permissions = new HashSet<String>();
roleNames.add("admin");
permissions.add("user.do?myjsp");
permissions.add("login.do?main");
permissions.add("login.do?logout");
//对比的过程
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(roleNames);
info.setStringPermissions(permissions);
return info;
}
}
对比的过程中如果存在则正确返回,否则返回error。
补充:
结合上篇博客的配置还想要多说两句
其一:SpringMVC拦截
这部分配置,是配置SpringMVC的拦截页面,看了这个配置相信大家也就明白了为什么我们访问的页面要加上.do(user.do?notmyjsp)吧!
<servlet-mapping>
<servlet-name>springMvc</servlet-name>
<!-- 只拦截带do后缀的 -->
<!-- <url-pattern>*.do</url-pattern> -->
<!-- 将springmvc的匹配表达式修改为所有的页面均拦截 -->
<url-pattern>/</url-pattern>
</servlet-mapping>
其二:ShiroFilter拦截
这部分配置是配置的ShiroFilter,也就是shiro拦截哪些页面。
<!-- Shiro主过滤器本身功能十分强大,其强大之处就在于它支持任何基于URL路径表达式的、自定义的过滤器的执行-->
<!-- Shiro Filter -->
<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>
<!-- shiro只拦截如下的后缀 -->
<filter-mapping>
<filter-name>shiroFilter</filter-name>
<url-pattern>*.action</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>shiroFilter</filter-name>
<url-pattern>*.do</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>shiroFilter</filter-name>
<url-pattern>*.jsp</url-pattern>
</filter-mapping>
其三:Shiro过滤链的定义(是否需要登录认证)
以下这部分配置,是配置访问的页面是否需要验证,即登录后才可以访问。举例说明:访问后缀名为.action的页面,我可以直接访问到,那么如果我访问.do的页面,则会自动跳转到登录页,需要我们首先登录后才可以访问,这些就与我们配置的过滤链相关。
<property name="filterChainDefinitions">
<value>
<!-- Shiro 过滤链的定义-->
<!--此处可配合这篇文章来理解各个过滤连的作用http://blog.csdn.net/jadyer/article/details/12172839-->
<!--
Anon:不指定过滤器
Authc:验证,这些页面必须验证后才能访问,也就是我们说的登录后才能访问。
-->
<!--下面value值的第一个'/'代表的路径是相对于HttpServletRequest.getContextPath()的值来的 -->
<!--anon:它对应的过滤器里面是空的,什么都没做,这里.do和.jsp后面的*表示参数,比方说login.jsp?main这种 -->
<!--authc:该过滤器下的页面必须验证后才能访问,它是Shiro内置的一个拦截器org.apache.shiro.web.filter.authc.FormAuthenticationFilter-->
/login.jsp* = anon
/login.do* = anon
/index.jsp*= anon
/error/noperms.jsp*= anon
/*.jsp* = authc
/*.do* = authc
</value>
</property>
这些过滤器分为两组,一组是认证过滤器,一组是授权过滤器。其中anon,authcBasic,auchc,user是第一组,
perms,roles,ssl,rest,port是第二组
可参考:http://blog.csdn.net/hxpjava1/article/details/7035724
扩展:
Shiro支持三种方式实现授权过程:
编码实现
注解实现
JSPTaglig实现
编程式:通过写if/else授权代码块完成(以上实例即使用编程式完成):
Subject subject = SecurityUtils.getSubject();
if(subject.hasRole(“admin”)) {
//有权限
} else {
//无权限
}
注解式:通过在执行的Java方法上放置相应的注解完成:
@RequiresRoles("admin")
public void hello() {
//有权限
}
没有权限将抛出相应的异常;
JSP标签:在JSP/GSP页面通过相应的标签完成:
<shiro:hasPermission name="user:create">
<a href="createUser.jsp">Create a new User</a>
</shiro:hasPermission>
总结:
无论是Shiro的登录认证还是授权,其实都是结合Subject,SecurityManager和Realms这三者的关系来实现的,理解了三者的关系Shiro也就学会了。Subject,当前用户;SecurityManager,外观的作用,其内部为我们封装了实现好的功能;Realms,Shiro和真实Dao操作的桥梁,以下这张图很形象的展示了三者的关系。