概念
- 授权:访问控制,即在应用中控制谁访问哪些资源。
- 主体: 访问应用的用户,Shiro里面的Subject代表该用户。
- 资源:Web应用里面体现为用户可以访问的URL。
- 权限:应用中,用户能不能访问某个资源。
- 角色:权限的集合。
授权方式
- 编程式:通常写
if/else
授权代码块完成。
if(subject.hasRole("admin")){
//有权限
}else{
//无权限
}
- 注解式(常用):通常在执行的Java方法上放置相应的注解完成,没有权限将抛出响应的异常。
@RequiresRoles("admin")
public void hello(){
//有权限
}
- JSP/GSP标签:在JSP/GSP页面通过相应的标签完成,隐藏没有权限的资源。
<shiro:hasRole name="admin">
<!-- 有权限 -->
</shiro:hasRole>
拦截器
默认的过滤器,共有一下几种:
身份验证相关的过滤器:
授权相关的:
其他:
配置权限
在applicationContext.xml中配置权限。
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<property name="securityManager" ref="securityManager"/>
<property name="loginUrl" value="/login.jsp"/>
<property name="successUrl" value="/list.jsp"/>
<property name="unauthorizedUrl" value="/unauthorized.jsp"/>
<!--
配置哪些页面需要受保护.
以及访问这些页面需要的权限.
1). anon 可以被匿名访问
2). authc 必须认证(即登录)后才可能访问的页面.
3). logout 登出.
4). roles 角色过滤器
-->
<property name="filterChainDefinitions">
<value>
/login.jsp = anon
/shiro/login = anon
/shiro/logout = logout
/user.jsp = roles[user]
/admin.jsp = roles[admin]
# everything else requires authentication:
/** = authc
</value>
</property>
</bean>
其中,user.jsp需要具有user
的角色,admin.jsp需要具有admin
的角色,才可以访问,否则跳转至unauthorized.jsp
授权Realm
(1)授权需要继承AuthorizingRealm
,并实现其doGetAuthorizationInfo
方法。
(2)AuthorizingRealm
继承自AuthenticatingRealm
,但没有实现AuthenticatingRealm
中的doGetAuthenticationInfo
方法,所以认证和授权只需要继承AuthorizingRealm
就可以了,同时实现他的两个抽象方法即可。(Authorization授权,Authentication认证)
实现授权Realm
使Realm继承自AuthorizingRealm
,实现doGetAuthorizationInfo
,就可以完成授权操作,实现doGetAuthenticationInfo
,就可以完成认证操作。
实现如下:
public class ShiroRealm extends AuthorizingRealm {
/*
* 认证
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
System.out.println("[FirstShiroRealm] doGetAuthenticationInfo: ");
// 1. 把AuthenticationToken 转换为UsernamePasswordToken
UsernamePasswordToken upToken = (UsernamePasswordToken) token;
// 2. 把UsernamePasswordToken 中来获取username
String username = upToken.getUsername();
// 3. 调用数据库的方法,从数据库中查询username 对应的用户记录.
System.out.println("从数据库中获 取username:" + username + " 所对应的用户信息.");
// 4.若用户不存在,则可以抛出UnknownAccountException 异常
if ("unknown".equals(username)) {
throw new UnknownAccountException("用户不存在");
}
// 5.根据用户信息的情况,决定是否需要抛出其他的AuthenticationException 异常.
if ("monster".equals(username)) {
throw new LockedAccountException("用户被锁定");
}
// 6.根据用户的情况,来构建AuthenticationInfo 对象并返回.
// 通常使用的实现类是SimpleAuthenticationInfo
// 以下信息是从数据库中获取的.
// (1)principal:认证的实体信息,可以是username,也可以是数据表对应的用户的实体类对象
Object principal = username;
// (2)credentials:密码.
Object credentials = null;// "fc1709d0a95a6be30bc5926fdb7f22f4";
if ("admin".equals(username)) {
credentials = "038bdaf98f2037b31f1e75b5b4c9b26e";
} else if ("user".equals(username)) {
credentials = "098d2c478e9c11555ce2823231e02ec1";
}
// (3)realmName:当前realm 对象的name,调用父类的getName()方法
String realmName = getName();
// (4)盐值:
ByteSource credentialsSalt = ByteSource.Util.bytes(username);
// AuthenticationInfo info = new SimpleAuthenticationInfo(principal,
// credentials, realmName);
AuthenticationInfo info = new SimpleAuthenticationInfo(principal, credentials, credentialsSalt, realmName);
return info;
}
/*
* 授权,会被shiro回调的方法
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
//1.从PrincipalCollection中获取登录用户的信息
Object principal = principals.getPrimaryPrincipal();
//2.利用登录的用户信息来获取当前用户的角色或权限(可能需要查询数据库)
Set<String> roles = new HashSet<>();
roles.add("user");
if("admin".equals(principal)) {
roles.add("admin");
}
//3.创建 SimpleAuthorizationInfo,并设置其roles属性
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(roles);
//4.返回SimpleAuthorizationInfo对象.
return info;
}
}
说明:doGetAuthorizationInfo
方法是进行授权的方法,返回值就是授权信息。
授权过程:
(1)从PrincipalCollection中获取登录用户的信息
(2)利用登录的用户信息来获取当前用户的角色或权限(可能需要查询数据库)
(3)创建 SimpleAuthorizationInfo,并设置其roles属性,代表其角色(权限)集合。
(4)返回SimpleAuthorizationInfo对象。