(六)shiro自定义realm

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



登录模拟


猜你喜欢

转载自blog.csdn.net/a1034386099/article/details/53178290