shiro快速入門案例


Apache Shiro是什么?

  • Apache Shiro是一個強大且易用的Java安全框架,可執行身份驗證(登錄)、授權、密碼學和會話管理

架構圖

組件基本說明:

  • subject(主體):接收客戶端賬號密碼,有一系列的認證授權方法
  • security manager(安全管理器):管理所有的subject,並使用底層組件完成操作
  • authenticator(認證/登錄校驗):對subject的身份進行認證,最簡單可以理解為對用戶的賬號密碼進行校驗
  • authorize(授權):subject認證通過后,在訪問功能時需要通過授權器判斷用戶是否有此功能的操作權限
  • realm(域):對當前subject的權限管理數據進行封裝(從數據庫中獲取),分別有認證和授權兩個
  • session manager(會話管理器):類似於web session域的session管理域
  • sessionDAO(會話DAO):shiro session的Dao類
  • cache manager(緩存管理器):用於緩存權限信息,提高系統性能
  • crypography(密碼學):一套加密api

快速入門案例

數據庫表:
user

user_role

role_permission

maven依賴:

<!-- shiro-core -->
<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-core</artifactId>
    <version>1.3.2</version>
</dependency>


<!-- 數據庫驅動:mysql -->
<dependency>
	<groupId>mysql</groupId>
	<artifactId>mysql-connector-java</artifactId>
	<version>5.1.38</version>
</dependency>


<!-- 連接池:druid -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.1.6</version>
</dependency>

** 數據庫工具類:**

public class DBUtil {

	private DBUtil() {}
	
	private static DruidDataSource druidDataSource = null;
	
	static {
		druidDataSource = new DruidDataSource();
		druidDataSource.setDriverClassName("com.mysql.jdbc.Driver");
		druidDataSource.setUrl("jdbc:mysql://127.0.0.1:3306/test");
		druidDataSource.setUsername("root");
		druidDataSource.setPassword("root");
	}
	
	public static DruidPooledConnection getConnection() throws SQLException {
		return druidDataSource.getConnection();
	}
	
	public static DataSource getDataSource() {
		return druidDataSource;
	}
	
}

** 需要認證授權的用戶信息(模擬表填提交的數據):**

public enum Users {
	ADMIN("admin", "123456"), TEST("test", "123456");
	
	private String username;
	private String password;
	Users(String username, String password) {
		this.username = username;
		this.password = password;
	}
	
	public String getUsername() {
		return username;
	}
	public void setUsername(String username) {
		this.username = username;
	}
	public String getPassword() {
		return password;
	}
	public void setPassword(String password) {
		this.password = password;
	}
	
}

** 入門案例: **

/**
 * 使用shiro提供的SimpleAccountRealm進行認證(不支持自定義授權)
 */
public class SimpleAccountRealmTest {
	
	//備用。用於存放查詢出來的角色名稱
	private static String[] userRoles = new String[5]; 
	
	//創建一個shiro提供的簡單Realm,不支持自定義授權
	private static SimpleAccountRealm realm = new SimpleAccountRealm();
	
	//初始化realm信息
	static {
		
		try {
			
			DruidPooledConnection connection = DBUtil.getConnection();
			
			//獲取需要認證用戶的user信息
			PreparedStatement userPrepareStatement = connection.prepareStatement("select * from user where username=?"); 
			userPrepareStatement.setString(1, Users.ADMIN.getUsername());
			ResultSet userRs = userPrepareStatement.executeQuery();
			userRs.next(); //username唯一所以只有一個rs
			
			//根據用戶信息(username)查找出對應的role
			PreparedStatement rolePrepareStatement = connection.prepareStatement("select * from user_role where username=?");
			rolePrepareStatement.setString(1, Users.ADMIN.getUsername());
			ResultSet roleRs = rolePrepareStatement.executeQuery();
			
			int i = 0;
			while(roleRs.next()) { //可能有多個角色
				userRoles[i++] = roleRs.getString("role_name");
			}
			
			
			/**
			 * 注意:這里的account信息應該是數據庫中的信息
			 */
			realm.addAccount(userRs.getString("username"), userRs.getString("password"), userRoles); //將該賬號信息設置到realm中
			
		} catch (Exception e) {
			e.printStackTrace();
		}
		
	}
	
	public static void main(String[] args) {
	
		// 1. 獲取默認的SecurityManager
		DefaultSecurityManager sm = new DefaultSecurityManager();
		sm.setRealm(realm);
		
		// 2. 設置到工具中
		SecurityUtils.setSecurityManager(sm);
		
		// 3. 獲取主體
		Subject subject = SecurityUtils.getSubject();
		
		// 4. 創建token
		UsernamePasswordToken token = new UsernamePasswordToken(Users.ADMIN.getUsername(), Users.ADMIN.getPassword());
		
		// 5. 認證
		subject.login(token);
		
		System.out.println( "是否認證成功: " + subject.isAuthenticated() );
		System.out.println( "是否有super這個角色: " +  subject.hasRole("super"));
		System.out.println( "是否有default這個角色: " +  subject.hasRole("default"));
//		boolean[] hasRoles = subject.hasRoles(Arrays.asList(userRoles)); //是否同時有super和default這個角色
		
		
	}

}

shiro提供的realm基本使用

** IniRealm: **
auth.ini:

[users]
admin=123456,super,default
test=123456,default

[roles]
super=user:delete,user:select,user:update,user:insert
default=user:select

code:

/**
 * 使用shiro提供的IniRealm進行認證(使用配置文件保存認證授權信息)
 */
public class IniRealmTest {
	
	private static IniRealm iniRealm;
	
	static {
		iniRealm = new IniRealm("classpath:auth.ini");
	}

	public static void main(String[] args) {

        

        // 1. 獲取默認的SecurityManager
        DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
        defaultSecurityManager.setRealm(iniRealm);

        // 2. 設置到工具中
        SecurityUtils.setSecurityManager(defaultSecurityManager);
        
        // 3. 獲取主體
        Subject subject = SecurityUtils.getSubject();

        // 4. 創建token
        UsernamePasswordToken token = new UsernamePasswordToken(Users.ADMIN.getUsername(), Users.ADMIN.getPassword());
//        UsernamePasswordToken token = new UsernamePasswordToken(Users.TEST.getUsername(), Users.TEST.getPassword());
//        UsernamePasswordToken token = new UsernamePasswordToken("AAAA", "XXX"); //UnknownAccountException 沒有該賬號
//        UsernamePasswordToken token = new UsernamePasswordToken(Users.TEST.getUsername(), "XXX"); //IncorrectCredentialsException 憑證錯誤(密碼錯誤)
        
        // 5. 認證
        subject.login(token);

		System.out.println( "是否認證成功: " + subject.isAuthenticated() );
		System.out.println( "是否有super這個角色: " +  subject.hasRole("super") );
		System.out.println( "是否有default這個角色: " +  subject.hasRole("default") );
		
		// 6. 授權
		System.out.println( "是否有user:select權限 " + subject.isPermitted("user:select"));
		System.out.println( "是否有user:delete權限 " + subject.isPermitted("user:delete"));
		System.out.println( "是否有user:update權限 " + subject.isPermitted("user:update"));
		System.out.println( "是否有user:insert權限 " + subject.isPermitted("user:insert"));

		
	}

}

** JdbcRealm: **

/**
 * 使用shiro提供的JdbcRealm進行認證(使用數據庫數據)
 */
public class JdbcRealmTest {

	private static JdbcRealm jdbcRealm;
	
	static {
		jdbcRealm = new JdbcRealm();
        jdbcRealm.setDataSource(DBUtil.getDataSource());
        jdbcRealm.setPermissionsLookupEnabled(true);	// 使用JdbcRealm時要設置權限開關,默認為false
        
        // 自定義SQL語句(如果不設置自定義的SQL語句則按照JdbcRealm內置的模板SQL語句進行數據庫操作,可以進入JdbcRealm查看)
        String sql = "select password from user where username = ?";
        jdbcRealm.setAuthenticationQuery(sql);

        String roleSql = "select role_name from user_role where username = ?";
        jdbcRealm.setUserRolesQuery(roleSql);
        
        String permissionSql = "select permission from role_permission where role_name = ?";
        jdbcRealm.setPermissionsQuery(permissionSql);
	}
	
	public static void main(String[] args) {

        // 1. 獲取默認的SecurityManager
        DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
        defaultSecurityManager.setRealm(jdbcRealm);

        // 2. 設置到工具中
        SecurityUtils.setSecurityManager(defaultSecurityManager);
        
        // 3. 獲取主體
        Subject subject = SecurityUtils.getSubject();

        // 4. 創建token
        UsernamePasswordToken token = new UsernamePasswordToken(Users.ADMIN.getUsername(), Users.ADMIN.getPassword());
//        UsernamePasswordToken token = new UsernamePasswordToken(Users.TEST.getUsername(), Users.TEST.getPassword());
//        UsernamePasswordToken token = new UsernamePasswordToken("AAAA", "XXX"); //UnknownAccountException 沒有改賬號
//        UsernamePasswordToken token = new UsernamePasswordToken(Users.TEST.getUsername(), "XXX"); //IncorrectCredentialsException 憑證錯誤(密碼錯誤)
        
        // 5. 認證
        subject.login(token);

		System.out.println( "是否認證成功: " + subject.isAuthenticated() );
		System.out.println( "是否有super這個角色: " +  subject.hasRole("super") );
		System.out.println( "是否有default這個角色: " +  subject.hasRole("default") );
		
		// 6. 授權
		System.out.println( "是否有user:select權限 " + subject.isPermitted("user:select"));
		System.out.println( "是否有user:delete權限 " + subject.isPermitted("user:delete"));
		System.out.println( "是否有user:update權限 " + subject.isPermitted("user:update"));
		System.out.println( "是否有user:insert權限 " + subject.isPermitted("user:insert"));
		
	}

}

自定義Realm(參考JdbcRealm)

** 輔助類: **

/**
 * MyRealm的輔助類(可以定義成內部類)
 */
public class UserDaoUtil {
	
	private UserDaoUtil(){ }
	
	private static Connection conn;

	static {
		try {
			conn = DBUtil.getConnection();
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
	
	
	/**
	 * 根據username獲取SimpleAccount
	 * @param username
	 * @param realmName
	 * @return
	 */
	public static SimpleAccount getSimpleAccount(String username, String realmName) {
		
		PreparedStatement prepareStatement = null;
		ResultSet rs = null;
		SimpleAccount account = null;
		try {
			
			prepareStatement = conn.prepareStatement("select * from user where username = ?");
			prepareStatement.setString(1, username);
			rs = prepareStatement.executeQuery();
			rs.next();
			
			account = new SimpleAccount(rs.getString("username"), rs.getString("password"), realmName);
			
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		return account;
	}
	
	
	/**
	 * 根據username獲取role
	 * @param username
	 * @return
	 */
	public static Set<String> getRoleNamesForUser(String username) {

		PreparedStatement prepareStatement = null;
		ResultSet rs = null;
		Set<String> roles = null;
		try {
			roles = new HashSet<>();
			prepareStatement = conn.prepareStatement("select * from user_role where username = ?");
			prepareStatement.setString(1, username);
			rs = prepareStatement.executeQuery();
			
			while(rs.next()) {
				roles.add( rs.getString("role_name") );
			}
			
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		return roles;
	}
	
	/**
	 * 獲取Permissions
	 * @param username
	 * @param roleNames
	 * @return
	 */
	public static Set<String> getPermissions(Set<String> roleNames) {
		
		PreparedStatement prepareStatement = null;
		ResultSet rs = null;
		Set<String> permissions = null;
		try {
			
			permissions = new HashSet<>();
			
			for (String roleName : roleNames) {
				
				prepareStatement = conn.prepareStatement("select * from role_permission where role_name = ?");
				prepareStatement.setString(1, roleName);
				rs = prepareStatement.executeQuery();
				
				while(rs.next()) {
					permissions.add(rs.getString("permission"));
				}
			}
			
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		return permissions;
	}
	
}

** 自定義Realm: **

public class MyRealmTest {

	private static MyRealm myRealm;
	
	static {
		myRealm = new MyRealm();
	}	
	
	public static void main(String[] args) {
		
        // 1. 獲取默認的SecurityManager
        DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
        defaultSecurityManager.setRealm(myRealm);

        // 2. 設置到工具中
        SecurityUtils.setSecurityManager(defaultSecurityManager);
        
        // 3. 獲取主體
        Subject subject = SecurityUtils.getSubject();

        // 4. 創建token
        UsernamePasswordToken token = new UsernamePasswordToken(Users.ADMIN.getUsername(), Users.ADMIN.getPassword());
//        UsernamePasswordToken token = new UsernamePasswordToken(Users.TEST.getUsername(), Users.TEST.getPassword());
//        UsernamePasswordToken token = new UsernamePasswordToken("AAAA", "XXX"); //UnknownAccountException 沒有改賬號
//        UsernamePasswordToken token = new UsernamePasswordToken(Users.TEST.getUsername(), "XXX"); //IncorrectCredentialsException 憑證錯誤(密碼錯誤)
        
        // 5. 認證
        subject.login(token);
		System.out.println( "是否認證成功: " + subject.isAuthenticated() );
		
		System.out.println("----------------------------------------------------------------");
		
		System.out.println( "是否有super這個角色: " +  subject.hasRole("super") );
		System.out.println( "是否有default這個角色: " +  subject.hasRole("default") );
		
		System.out.println("----------------------------------------------------------------");
		
		// 6. 授權
		System.out.println( "是否有user:select權限 " + subject.isPermitted("user:select"));
		System.out.println( "是否有user:delete權限 " + subject.isPermitted("user:delete"));
		System.out.println( "是否有user:update權限 " + subject.isPermitted("user:update"));
		System.out.println( "是否有user:insert權限 " + subject.isPermitted("user:insert"));
	}

}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM