在web开发过程中, 我们经常会碰到安全问题,哪些用户有权限访问,哪些用户没有权限访问,都是我们急需解决的.
接下来介绍一下Shiro框架:
一.Apache Shiro是一个强大易用的Java安全框架,提供了认证、授权、加密和会话管理等功能:
1)认证 - 用户身份识别,常被称为用户“登录”;
2)授权 - 访问控制;
3)密码加密 - 保护或隐藏数据防止被偷窥;
4)会话管理 - 每用户相关的时间敏感的状态。
对于任何一个应用程序,Shiro都可以提供全面的安全管理服务。并且相对于其他安全框架,Shiro要简单的多。
二.Shiro的三个核心组件:Subject, SecurityManager 和 Realms
1)Subject:即“当前操作用户”。但是,在Shiro中,Subject这一概念并不仅仅指人,也可以是第三方进程、后台帐户(Daemon Account)或其他类似事物。
它仅仅意味着“当前跟软件交互的东西”。但考虑到大多数目的和用途,你可以把它认为是Shiro的“用户”概念。Subject代表了当前用户的安全操
作,SecurityManager则管理所有用户的安全操作。
2)SecurityManager:它是Shiro框架的核心,典型的Facade模式,Shiro通过SecurityManager来管理内部组件实例,并通过它来提供安全管理的各种服务。
3)Realm: Realm充当了Shiro与应用安全数据间的“桥梁”或者“连接器”。也就是说,当对用户执行认证(登录)和授权(访问控制)验证时,Shiro会从应用配
置的Realm中查找用户及其权限信息。从这个意义上讲,Realm实质上是一个安全相关的DAO:它封装了数据源的连接细节,并在需要时将相关数据提供给
Shiro。当配置Shiro时,你必须至少指定一个Realm,用于认证和(或)授权。配置多个Realm是可以的,但是至少需要一个。
三. 环境配置:
1)配置描述符文件(web.xml):
<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>
<filter-mapping>
<filter-name>shiroFilter</filter-name>
<url-pattern>/*</url-pattern>//对每个请求都要进行权限认证;
</filter-mapping>
2)配置文件shiro-config.xml :
a. 添加ShiroFilter定义:
<!-- Shiro Filter -->
<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="/success.jsp" />
<property name="filterChainDefinitions">
<value>
/Login.action = anon
/goLogin.action = anon
/** = authc
</value>
</property>
</bean>
b securityManager定义:
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager" >
<property name="realm" ref="shiroRealm" />
<property name="cacheManager" ref="cacheManager" />
</bean>
c. 添加自定义Realm:
<!-- 項目自定义的Realm -->
<bean id="shiroRealm" class="starview.common.account.service.ShiroRealm">//对应的类;
<property name="isDebug">
<value>false</value>
</property>
<property name="allPermissions">
<list>
<value>program:list</value>
<value>program:edit</value>
<value>program:audit</value>
<value>DYBJ</value>
<value>DYSH</value>
</list>
</property>
</bean>
四. 实现上述自定义的Realm:
<span style="font-size:12px;">public class ShiroRealm extends AuthorizingRealm{
private static Logger logger = Logger.getLogger(Logger.class);
private String isDebug = "false";
private List<String> allPermissions;
/**
* 认证回调函数,登录时调用.
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) throws AuthenticationException{
logger.info("**********Enter the doGetAuthenticationInfo: 认证回调函数,登录时调用");
try{
UsernamePasswordToken token = (UsernamePasswordToken) authcToken;
String userName = token.getUsername();
char[] pwd = token.getPassword();
// 比较数据库中的用户名密码
ShiroUser shiroUser = new ShiroUser(1L,userName,userName);
return new SimpleAuthenticationInfo(shiroUser, pwd, userName);
}catch(Exception err){
logger.error("Failed to doGetAuthenticationInfo", err);
return null;
}
}
/**
* 授权查询回调函数, 进行鉴权但缓存中无用户的授权信息时调用.
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
// TODO Auto-generated method stub
try{
logger.info("Enter the doGetAuthorizationInfo : 授权查询回调函数");
ShiroUser shiroUser = (ShiroUser) principals.getPrimaryPrincipal();
String loginName = shiroUser.loginName;
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
if("true".equalsIgnoreCase(isDebug)){//调试模式;
logger.info("Enter the debug mode. allPermissions=" + allPermissions);
//参数isDebug和allPermissions都是从shiro-config.xml文件传过来的,必须用get set方法才能获取;
info.addStringPermissions(allPermissions);
//自定义的shiro标签写入key里面;
List<String> list = new ArrayList<String>();
list.add("AAA");
list.add("BBB");
info.addStringPermissions(list);
}
else{//非调试模式;
//从数据库中获取用户所用有的权限,放入info中;
}
return info;
}catch(Exception err) {
logger.error("Failed to doGetAuthorizationInfo", err);
return null;
}
}
public String getIsDebug() {
return isDebug;
}
public void setIsDebug(String isDebug) {
this.isDebug = isDebug;
}
public List<String> getAllPermissions() {
logger.info("*********allPermissions :" + allPermissions);
return allPermissions;
}
public void setAllPermissions(List<String> allPermissions) {
logger.info("*********allPermissions :" + allPermissions);
this.allPermissions = allPermissions;
}
/**
* 自定义Authentication对象,使得Subject除了携带用户的登录名外还可以携带更多信息.
*/
public static class ShiroUser implements Serializable {
private static final long serialVersionUID = -1373760761780840081L;
public Long id;
public String loginName;
public String name;
public ShiroUser(Long id, String loginName, String name) {
this.id = id;
this.loginName = loginName;
this.name = name;
}
public String getName() {
return name;
}
}</span>
五.登录部分:登录时候,如果认证通过,则调用此函数,之后会直接调用四中的认证回调函数
<pre name="code" class="java"> public static final void setLogin(String userName, String userPassword) {
Subject currentUser = SecurityUtils.getSubject();
if (!currentUser.isAuthenticated()) {
// collect user principals and credentials in a gui specific manner
// such as username/password html form, X509 certificate, OpenID,
// etc.
// We'll use the username/password example here since it is the most
// common.
// (do you know what movie this is from? ;)
UsernamePasswordToken token = new UsernamePasswordToken(userName,
userPassword);
// this is all you have to do to support 'remember me' (no config -
// built in!):
token.setRememberMe(true);
currentUser.login(token);
}
}
六.要在jsp中使用shiro框架,必须通过标签引入:
<%@
七.如何使用shiro标签:
1)系统自带的标签:只要环境配置好之后,直接使用即可
<shiro:guest>
欢迎游客访问,<a href="${pageContext.request.contextPath}/login.jsp">登录</a>
</shiro:guest>
参考文档:http://jinnianshilongnian.iteye.com/blog/2026398
2)自定义的一些标签:
<shiro:hasPermission name="ADTPGL">
<a target="myFrame" href="${basePath }/picture/picturelist.action" οnclick="setMenu(<%out.print(i);i++;%>);"><s:text name="menu.TPGL" /></a>
<span style="font-family:Monaco,'DejaVu sans Mono','Bitstream Vera sans Mono',Consolas,'Courier new',monospace;"> </span></shiro:hasPermission>
像这种自定义的标签,我们必须把他的name值放入shiro的SimpleAuthorizationInfo中,也就是在四中的
授权查询回调函数
中使用:
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
info.addStringPermissions("ADTPGL");
八. 在七中,不管是自定义的标签还是系统本身自带的标签都被存放在了info当中,当访问一个页面时,页面上的每一个shiro标签都会自动在info
当中查找相应的key值,如果查找到了,就有权限访问,如果没查找到,就无权限访问;
九 为了说明这篇文章,特意写了一个demo,大家可以去下载:http://download.csdn.net/detail/wangyi201212/8720311
十.效果图
附件:1.shrio 权限管理filterChainDefinitions过滤器配置
http://www.cppblog.com/guojingjia2006/archive/2014/05/14/206956.html