Shiro从从Realm获取安全数据(如用户、角色、权限),就是说SecurityManager要验证用户身份,那么它需要从Realm获取相应的用户进行比较以确定用户身份是否合法;也需要从Realm得到用户相应的角色/权限进行验证用户是否能进行操作;可以把Realm看成DataSource,即安全数据源。
现在我们自定义realm,把用户、角色和权限都存入数据库中,我们自定义一个realm从数据空中访问数据,并为登录的用户添加角色和权限。我们在数据库中设计三个表t_user、t_role和t_permission。三个表之间的关系如下,并插入数据
本节是在web环境下模拟,可以查看上一节的web内容,这一节添加自定义的realm
自定义的realm的需要继承 一个抽象类:AuthorizingRealm,并实现两个方法doGetAuthorizationInfo()和doGetAuthenticationInfo()。
doGetAuthorizationInfo()方法用于给登录的用户赋予角色和权限
doGetAuthenticationInfo()方法用于认证登录的用户
shiro默认使用JdbcRealm作为访问数据库中的数据,但是里面访问的表的字段已经被写死,我们根据业务需求需要定义自己的字段。但基本的代码过程可以参考它。
package com.liy.realm;
import java.sql.Connection;
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.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import com.liy.dao.UserDao;
import com.liy.entity.User;
import com.liy.util.DbUtil;
/**
* 自己定义的realm
* @author 荔荔
*
*/
public class MyRealm extends AuthorizingRealm{
UserDao userDao = new UserDao();
DbUtil dbUtil = new DbUtil();
/**
* 授权,为当前登录的用户授予角色和权限,第二步
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
//获取认证信息中的用户名,即authenticationInfo中的用户名
String userName=(String) principals.getPrimaryPrincipal();
//创建一个权限信息类
SimpleAuthorizationInfo authorizationInfo= new SimpleAuthorizationInfo();
Connection con = null;
try {
con=dbUtil.getCon();
//为这个权限信息实例设置角色和权限
authorizationInfo.setRoles(userDao.getRoles(con,userName));
authorizationInfo.setStringPermissions(userDao.getPermissions(con,userName));
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
try {
dbUtil.closeCon(con);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return authorizationInfo;
}
/**
* 认证当前登录的用后,第一步
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
//获取身份信息,因为登录的时候已经把userName存入token中了
String userName=(String) token.getPrincipal();
Connection con=null;
try {
con=dbUtil.getCon();
User user=userDao.getByUserName(con, userName);
//查找的用户名存在
if(user !=null){
//创建一个认证信息,判断密码是否匹配
AuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(user.getUserName(),user.getPassword(),"xx");
return authenticationInfo;
}else{
return null;
}
} catch (Exception e) {
e.printStackTrace();
}finally{
try {
dbUtil.closeCon(con);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return null;
}
}
userDao中的方法
package com.liy.dao;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashSet;
import java.util.Set;
import com.liy.entity.User;
public class UserDao {
/**
* 通过userName获取User
* @param con
* @param userName
* @return
* @throws Exception
*/
public User getByUserName(Connection con,String userName)throws Exception{
User currentUser=null;
String sql="select * from t_user where username = ?";
PreparedStatement pstm= con.prepareStatement(sql);
pstm.setString(1, userName);
ResultSet rs=pstm.executeQuery();
while(rs.next()){
currentUser= new User();
currentUser.setId(rs.getInt("id"));
currentUser.setUserName(rs.getString("userName"));
currentUser.setPassword(rs.getString("password"));
}
return currentUser;
}
/**
* 根据userName获取它的角色
* @param con
* @param userName
* @return
* @throws SQLException
*/
public Set<String> getRoles(Connection con, String userName) throws SQLException {
Set<String> roles = new HashSet<String>();
String sql = "select * from t_user t1,t_role t2 where t1.roleId=t2.id and t1.userName=?";
PreparedStatement pstm=con.prepareStatement(sql);
pstm.setString(1, userName);
ResultSet rs=pstm.executeQuery();
while(rs.next()){
roles.add(rs.getString("roleName"));
}
return roles;
}
/**
* 根据userName获取权限,这就涉及了三表查询
* @param con
* @param userName
* @return
* @throws SQLException
*/
public Set<String> getPermissions(Connection con, String userName) throws SQLException {
Set<String> permissions = new HashSet<String>();
String sql = "SELECT * FROM t_user t1,t_role t2,t_permission t3 WHERE t1.roleId=t2.id AND t2.id=t3.roleId AND t1.userName=?";
PreparedStatement pstm= con.prepareStatement(sql);
pstm.setString(1, userName);
ResultSet rs=pstm.executeQuery();
while(rs.next()){
permissions.add(rs.getString("permission"));
}
return permissions;
}
}
自定义的realm编写完毕,我们需要web环境加载的时候就能启用,所有还要配置shiro.ini文件
[main]
#身份认证没有成功跳转这个URL
authc.loginUrl = /login
#角色认证未通过
roles.unauthorizedUrl=/unauthorized.jsp
#权限认证未通过
perms.unauthorizedUrl=/unauthorized.jsp
#配置自定义realm
myRealm=com.liy.realm.MyRealm
#把我们自定义的realm赋值给securityManager
securityManager.realms=$myRealm
[urls]
#请求login不需要身份认证,不然进入死循环
/login=anon
#进入比较敏感的URL需要身份认证
/admin=authc
/student=roles[teacher]
/teacher=perms["user:create"]
t_user表
t_role
t_permission
登录模拟