Shiro 是一个用 Java 语言实现的框架,通过一个简单易用的 API 提供身份验证和授权。使用 Shiro,您就能够为您的应用程序提供安全性而又无需从头编写所有代码。
由于最近学习用到shiro,分享一下自己使用和剖析的经过。
首先是shiro的核心功能
shiro的基本调用调用关系
步骤如下:
1.首先设置web.xml文件引入shiro的过滤器
shiroFilter
org.springframework.web.filter.DelegatingFilterProxy
targetFilterLifecycle
true
OpenSessionInViewFilter
/*
shiroFilter
/*
struts2
/*
2.在spring中引入shiro的相关核心类
Shiro安全配置
/index.jsp* = anon
/home* = anon
/sysadmin/login/login.jsp* = anon
/sysadmin/login/logout.jsp* = anon
/login* = anon
/logout* = anon
/staticfile/** = anon
/** = authc
package cn.tarena.ht.shiro;
import java.util.List;
import org.apache.log4j.Logger;
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.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import cn.tarena.ht.domain.User;
import cn.tarena.ht.service.UserService;
public class AuthRealm extends AuthorizingRealm{
private static Logger log = Logger.getLogger(AuthRealm.class);
//spring框架注入,将shiro和spring整合。
private UserService userService;
public void setUserService(UserService userService) {
this.userService = userService;
}
//授权 此方法每遇到shiro标签或者注解都会执行一次
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
log.info("授权");
//从principals中获取第一个元素,它就是当前用户对象
User _user = (User)principals.fromRealm(getName()).iterator().next();
String username = _user.getUsername();
//获取到所有角色权限的字符串,采用缓存可以大幅度减少查询次数
List
permissionList = userService.getModuleByUsername(username);
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
info.addStringPermissions(permissionList); //将权限串集合,内部进行比较
return info;
}
//认证(登录)
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
log.info("认证");
//获取spring容器中的bean
UsernamePasswordToken uToken = (UsernamePasswordToken)token;
User _user = userService.findByUsername(uToken.getUsername()); //持久化
AuthenticationInfo info = null;
if(_user!=null){
//参数:数据库的用户,数据库中的密码(加密后),当前的自定义realm
info = new SimpleAuthenticationInfo(_user,_user.getPassword(),getName());
}
return info;
}
}
4.如果需要自己制定加密方法要继承
SimpleCredentialsMatcher
并把实现类注入给shiro,见spring配置文件
package cn.tarena.ht.shiro;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authc.credential.SimpleCredentialsMatcher;
import org.apache.shiro.crypto.hash.Md5Hash;
public class CustomCredentialsMatcher extends SimpleCredentialsMatcher {
public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
UsernamePasswordToken usertoken = (UsernamePasswordToken) token;
//注意token.getPassword()拿到的是一个char[],不能直接用toString(),它底层实现不是我们想的直接字符串,只能强转
String salt = usertoken.getUsername();
Object tokenCredentials =md5(String.valueOf(usertoken.getPassword()),salt);
Object accountCredentials = getCredentials(info);
//将密码加密与系统加密后的密码校验,内容一致就返回true,不一致就返回false
return equals(tokenCredentials, accountCredentials);
}
//高强度加密算法,不可逆 salt=username+id
public String md5(String password, String salt){
return new Md5Hash(password,"zs"+salt,2).toString();
}
}
shiro的登入认证:
public String login(){
if(userName==null||password==null)
return "login";
AuthenticationToken token=new UsernamePasswordToken(userName,password);
SecurityUtils.setSecurityManager(securityManager);
Subject sub=SecurityUtils.getSubject();
try{
sub.login(token);
User _user=(User)sub.getPrincipal();
System.out.println(_user.getDept().getDeptName());//防止跳转造成懒加载问题
session.put(SysConstant.CURRENT_USER_INFO, _user); //记录session
return SUCCESS;
}catch(Exception e){
String msg = "登录错误,请重新填写用户名密码!";
this.setErrorInfo(msg);
return "login";
}
shiro网站中的权限菜单控制:
@RequiresPermissions("系统管理")
public String list(){
List
dataList = deptService.find("from Dept o", Dept.class, null);
super.put("dataList", dataList);
return "plist";
}
以上是基本shiro功能的使用,附上授权和认证的流程图:
shiro的教科书式网站:http://www.ibm.com/developerworks/cn/web/wa-apacheshiro/