1. 下载
在Maven项目中的依赖配置如下:
org.apache.shiro
shiro-core
1.3.2
org.apache.shiro
shiro-web
1.3.2
org.slf4j
slf4j-api
1.7.25
org.slf4j
slf4j-jcl
1.7.25
commons-logging
commons-logging1.2
特别地!Shiro使用了日志框架slf4j,因此需要对应配置指定的日志实现组件,如:log4j,logback等。
而且,由于shiro-web组件使用apache commons logging组件中的工具类,所以在项目中必须添加commongs logging组件。
否则,程序启动时将会报错:
java.lang.NoClassDefFoundError: org/apache/commons/logging/LogFactory
at org.apache.commons.beanutils.ConvertUtilsBean.(ConvertUtilsBean.java:157)
at org.apache.commons.beanutils.BeanUtilsBean.(BeanUtilsBean.java:117)
at org.apache.commons.beanutils.BeanUtilsBean$1.initialValue(BeanUtilsBean.java:68)
at org.apache.commons.beanutils.ContextClassLoaderLocal.get(ContextClassLoaderLocal.java:153)
at org.apache.commons.beanutils.BeanUtilsBean.getInstance(BeanUtilsBean.java:80)
at org.apache.commons.beanutils.PropertyUtilsBean.getInstance(PropertyUtilsBean.java:114)
at org.apache.commons.beanutils.PropertyUtils.getPropertyDescriptor(PropertyUtils.java:460)
at org.apache.shiro.config.ReflectionBuilder.isTypedProperty(ReflectionBuilder.java:409)
at org.apache.shiro.config.ReflectionBuilder.applyProperty(ReflectionBuilder.java:702)
at org.apache.shiro.config.ReflectionBuilder.applySingleProperty(ReflectionBuilder.java:364)
at org.apache.shiro.config.ReflectionBuilder.applyProperty(ReflectionBuilder.java:325)
at org.apache.shiro.config.ReflectionBuilder$AssignmentStatement.doExecute(ReflectionBuilder.java:955)
at org.apache.shiro.config.ReflectionBuilder$Statement.execute(ReflectionBuilder.java:887)
at org.apache.shiro.config.ReflectionBuilder$BeanConfigurationProcessor.execute(ReflectionBuilder.java:765)
at org.apache.shiro.config.ReflectionBuilder.buildObjects(ReflectionBuilder.java:260)
at org.apache.shiro.config.IniSecurityManagerFactory.buildInstances(IniSecurityManagerFactory.java:167)
at org.apache.shiro.config.IniSecurityManagerFactory.createSecurityManager(IniSecurityManagerFactory.java:130)
at org.apache.shiro.config.IniSecurityManagerFactory.createSecurityManager(IniSecurityManagerFactory.java:108)
at org.apache.shiro.config.IniSecurityManagerFactory.createInstance(IniSecurityManagerFactory.java:94)
at org.apache.shiro.config.IniSecurityManagerFactory.createInstance(IniSecurityManagerFactory.java:46)
at org.apache.shiro.config.IniFactorySupport.createInstance(IniFactorySupport.java:123)
at org.apache.shiro.util.AbstractFactory.getInstance(AbstractFactory.java:47)
at org.apache.shiro.web.env.IniWebEnvironment.createWebSecurityManager(IniWebEnvironment.java:203)
....
2.集成Shiro
在Java Web应用中使用Shiro,需要特别的集成方式,不再像在非Web环境的独立应用中使用Shiro那么简单(只需要下载Shiro并添加到项目即可)。
通常,在Java Web应用中集成框架都是从配置web.xml开始的,集成Shiro也不例外。
web.xml:
org.apache.shiro.web.env.EnvironmentLoaderListener
ShiroFilter
org.apache.shiro.web.servlet.ShiroFilter
ShiroFilter
/*
REQUEST
FORWARD
INCLUDE
ERROR
通常,在Java Web应用中集成第三方框架,都是从Filter开始。Shiro也是如此,即需要将所有请求都经过Shiro指定的Filter进行拦截,这样才能完成用户对指定资源访问的授权验证。
特别地,从Shiro 1.2+版本之后,在Java Web应用中集成Shiro非常简单,甚至都不需要明确指定shiro配置文件的路径,而是直接在web.xml中添加org.apache.shiro.web.env.EnvironmentLoaderListener即可(只需要保证在${webapp}/WEB-INF/目录下存在文件shiro.ini)。
3. 数据源配置
在Shiro中,Realm定义了访问数据的方式,用来连接不同的数据源,如:LDAP,关系数据库,配置文件等等。
Realm类图:
也就是说,可以根据实际需求及应用的权限管理复杂度灵活选择指定数据源。
在此,以org.apache.shiro.realm.text.IniRealm为例,具体配置如下:
shiro.ini:
[main]# 自定义过滤器
sessionFilter=org.chench.test.shiroweb.filter.SessionFilter
authc.loginUrl=/index
ssl.enabled=false
# -----------------------------------------------------------------------------
# Users and their (optional) assigned roles
# username= password, role1, role2, ...,roleN
# -----------------------------------------------------------------------------[users]root= secret,admin
guest= guest,guest
presidentskroob= 12345,president
darkhelmet= ludicrousspeed, darklord,schwartz
lonestarr= vespa, goodguy,schwartz
# -----------------------------------------------------------------------------
# Roles with assigned permissions
# roleName= perm1, perm2, ...,permN
# -----------------------------------------------------------------------------[roles]admin=*
schwartz=lightsaber:*
goodguy=winnebago:drive:eagle5
# -----------------------------------------------------------------------------
# The format of each line in the urls section is as follows:
# _URL_Ant_Path_Expression_=_Path_Specific_Filter_Chain_
# -----------------------------------------------------------------------------[urls]/index= anon,sessionFilter
/user/signin=anon
/user/login=anon
/user/**=authc
/home/**=authc
#/admin/**= authc, roles[administrator]#/rest/**= authc,rest
#/remoting/rpc/**= authc, perms["remote:invoke"]
4. 认证
在Shiro中,认证即执行用户登录,读取指定Realm连接的数据源,以验证用户身份的有效性与合法性。
关于Shiro在Web应用中的认证流程,与Shiro在非Web环境的独立应用中的认证流程一样,都需要执行用户登录,即:
Subject currentUser =SecurityUtils.getSubject();if(!currentUser.isAuthenticated()) {
UsernamePasswordToken token= newUsernamePasswordToken(name, password);try{
currentUser.login(token);
}catch(UnknownAccountException e) {
exception=e;
logger.error(String.format("user not found: %s", name), e);
}catch(IncorrectCredentialsException e) {
exception=e;
logger.error(String.format("user: %s pwd: %s error", name, password), e);
}catch(ConcurrentAccessException e) {
exception=e;
logger.error(String.format("user has been authenticated: %s", name), e);
}catch(AuthenticationException e) {
exception=e;
logger.error(String.format("account except: %s", name), e);
}
}
唯一的区别就是,在Java Web环境中,用户名和密码参数是通过前端页面进行传递。
5. 授权
需要再三强调!!!Shiro作为权限框架,仅仅只能控制对资源的操作权限,并不能完成对数据权限的业务需求。
而对于Java Web环境下Shiro授权,包含个方面的含义。
其一,对于前端来说,用户只能看到他对应访问权限的元素。
其二,当用户执行指定操作(即:访问某个uri资源)时,需要验证用户是否具备对应权限。
对于第一点,在Java Web环境下,通过Shiro提供的JSP标签实现。
用户管理
操作审计
必须在jsp页面中引入shiro标签库:
对于第二点,与在非Java Web环境下一样,需要在后端调用API进行权限(或者角色)检验。如果在Spring框架中集成Shiro,还可以直接通过Java注解方式实现。
api调用:
String roleAdmin = "admin";
Subject currentUser=SecurityUtils.getSubject();if(!currentUser.hasRole(roleAdmin)) {//todo something
}