Apache Shiro入门总结

一:数据库表结构
   users:用户表,包含用户名、密码、角色ID。
   roles:角色表,包含角色名。
   permission:权限表,包含权限字符串(user:add),权限描述。
   role_permission:中间表,包含角色和权限的id。

二:SecurityManager和Subject
   SecurityManager是shiro的核心,它是一个facade,所有的交互最终都通过SecurityManager执行。Subject代表当前应用的参与者,可以是一个用户,也可以是第三方服务等其他抽象参与者。一般的shiro操作都是操作Subject就行。下面是一些常用方法。

Subject currentUser = SecurityUtils.getSubject();//获取当前用户
currentUser.getSession();  //获取会话
currentUser.checkPermission("printer:print");//检查是否有对应权限
currentUser.checkRole("管理员");//检查是否有对应角色
currentUser.logout(); //执行登出操作,移除对应的session以及权限数据。


三:Wildcard Permissions
     shiro默认使用一种类似"printer:print:lp7200"的语法来标识权限。这三部分分别为域、动作、实例。一般使用域+动作就可以了,如删除用户,可以用"user:delete"。
    通配符"*"和","可以用在任何一个部分。如"printer:*:lp7200,jet40",表示可以在打印机lp7200、jet40上执行所有操作。

四:自定义Realm
    Realm是一个用于访问诸如用户、角色、权限这类安全数据的组件。实际应用中这些数据一般保存在数据库里,因此需要自定义realm实现安全数据的访问。虽然shiro自身提供了JdbcRealm,但是这需要数据库表设计和shiro默认的一致,开发者可根据实际情况选择。

package com.my.shiro.dao;

import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.apache.shiro.authc.AccountException;
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.AuthorizationException;
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.my.shiro.model.Permission;
import com.my.shiro.model.User;
public class MyJdbcRealm extends AuthorizingRealm {

	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
		if (principals == null) {
            throw new AuthorizationException("PrincipalCollection method argument cannot be null.");
        }
        String username = (String) getAvailablePrincipal(principals);
        User user = User.dao.getByUserName(username);
        int roleid = user.getInt("role_id");
        List<Permission> perms = Permission.dao.getPermissions(roleid);
        Set<String> roleSet = new HashSet<String>();
        roleSet.add(String.valueOf(roleid));
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(roleSet);
        info.setStringPermissions(getPermissionSet(perms));
		return info;
	}

	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(
			AuthenticationToken token) throws AuthenticationException {
		UsernamePasswordToken upToken = (UsernamePasswordToken) token;
        String username = upToken.getUsername();
        
        if (username == null) {
            throw new AccountException("Null usernames are not allowed by this realm.");
        }
        String password = User.dao.getPwdByUserName(username);
        if(password==null)
        	throw new AccountException("account error...");
        AuthenticationInfo info = new SimpleAuthenticationInfo(username, password, getName());
		return info;
	}
	
	private Set<String> getPermissionSet(List<Permission> perms){
		Set<String> set = new HashSet<String>();
		for(Permission p:perms){
			set.add(p.getStr("pkey"));
		}
		return set;
	}
} 

doGetAuthenticationInfo(AuthenticationToken token)是根据用户名从数据库获取用户名、密码组成一个AuthenticationInfo,此时还未进行验证,该对象用于之后和用户提交的密码(未加密、加密)进行匹配。
doGetAuthorizationInfo(PrincipalCollection principals)此时已经验证成功,此方法根据用户名获取对应的角色和权限。

五:web.xml配置

<listener> <listener-class>org.apache.shiro.web.env.EnvironmentLoaderListener</listener-class> </listener>
 <filter>
     <filter-name>ShiroFilter</filter-name>
     <filter-class>org.apache.shiro.web.servlet.ShiroFilter</filter-class>
  </filter>
   <filter-mapping>
     <filter-name>ShiroFilter</filter-name>
     <url-pattern>/*</url-pattern>
 </filter-mapping>	
这个是shiro1.2后的filter配置。此filter建议放在其他filter之前,使shiro能正常工作。


六:shiro.ini配置
  包含main,users,roles,urls四个section。当使用数据库存储时,users,roles在这里用不到。main用于配置SecurityManager及其依赖,如Realm。urls是web应用特有的,用于根据url设置访问权限。

[main]
myRealm=com.my.shiro.dao.MyJdbcRealm
securityManager.realms=$myRealm
user.loginUrl=/
perms.unauthorizedUrl=/common/unauthor.jsp
[urls]
/common/**=anon
/security/**=user
/admin/**=user,perms["admin:*"]
user.loginUrl定义未验证时的跳转路径,perms.unauthorizedUrl定义无权限时的跳转路径。
urls区域中,左边为访问的url路径,右边为过滤器,可以有多个形成过滤器链。shiro提供了一些默认的过滤器。
anon org.apache.shiro.web.filter.authc.AnonymousFilter
authc org.apache.shiro.web.filter.authc.FormAuthenticationFilter
authcBasic org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter
logout org.apache.shiro.web.filter.authc.LogoutFilter
noSessionCreation org.apache.shiro.web.filter.session.NoSessionCreationFilter
perms org.apache.shiro.web.filter.authz.PermissionsAuthorizationFilter
port org.apache.shiro.web.filter.authz.PortFilter
rest org.apache.shiro.web.filter.authz.HttpMethodPermissionFilter
roles org.apache.shiro.web.filter.authz.RolesAuthorizationFilter
ssl org.apache.shiro.web.filter.authz.SslFilter
user org.apache.shiro.web.filter.authc.UserFilter
如果要验证才能访问的路径,可以用authc或user。authc必须是验证过的,不能是"remember me",而user可以是"remember me",只要Subject包含principal就行。


七:登录

public void doLogin(){
		String username = getPara("username");
		String password = getPara("password");
		UsernamePasswordToken token = new UsernamePasswordToken(username, password);
		Subject user = SecurityUtils.getSubject();
		try{
			user.login(token);
		}catch (AuthenticationException e) {
			redirect(getRequest().getContextPath()+"/");
			return;
		}
		//登录成功
		redirect(getRequest().getContextPath()+"/page/index");
	}
八:方法级的权限控制
使用上面的url配置可以基于路径进行粗颗粒度的权限控制,shiro提供了一些注释,配合其他AOP框架,可以实现方法级的权限控制。如:
@RequiresAuthentication
@RequiresGuest
@RequiresPermissions("account:create")
@RequiresUser

默认的都是Logical.ALL,就是必须全部满足。当只需一个时可以使用Logical.OR。
这些权限注释可以作用在类或者方法上,来控制类中个别或者全部方法的权限访问。

九:JSP Taglib 权限控制

<%@ taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>
<shiro:authenticated>
    <a href="updateAccount.jsp">Update your contact information</a>.
</shiro:authenticated>

你可能感兴趣的:(Apache Shiro入门总结)