當shiro內置的IniRealm和JdbcRealm都不滿足我們的要求時,怎麼辦呢?別擔心,shiro還爲我們考慮到了這個情況,我們可以繼承AuthorizingRealm,然後重寫doGetAuthorizationInfo和doGetAuthenticationInfo這兩個方法就可以了。doGetAuthorizationInfo方法重寫我們需要授權的代碼,doGetAuthenticationInfo方法重寫我們需要認證的代碼,廢話不多說,直接上圖和代碼。
1. 在博客一的基礎上,shiroTest.java同路徑文件夾下新建一個CutomRealm.java文件
代碼如下
public class CustomRealm extends AuthorizingRealm {
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
// TODO Auto-generated method stub
return null;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
// TODO Auto-generated method stub
return null;
}
}
表示CustomRealm繼承了AuthorizingRealm類,並且需要覆蓋重寫doGetAuthorizationInfo和doGetAuthenticationInfo這兩個方法
2. 重寫doGetAuthenticationInfo方法表示我們需要進行認證的過程
代碼如下
// 模擬數據庫存放用戶名和密碼
Map<String,String> userMap=new HashMap<String,String>();
{
userMap.put("zhangsan", "123");
userMap.put("lisiplus", "456");
super.setName("CustomerRealm");
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
// TODO Auto-generated method stub
// 從subject客體中取得當前用戶名
String userName=(String)token.getPrincipal();
// 模擬從數據庫取得當前用戶名對應的密碼
String password=getPasswordByUsername(userName);
if(password==null)
{
return null;
}
// 取的當前認證的信息
SimpleAuthenticationInfo simpleAuthenticationInfo=new SimpleAuthenticationInfo(userName,password,"CustomerRealm");
return simpleAuthenticationInfo;
}
private String getPasswordByUsername(String userName) {
// TODO Auto-generated method stub
return userMap.get(userName);
}
3. 新建一個用於測試CustomRealmTest.java文件
代碼如下
public class CustomRealmTest {
@Test
public void Test() {
CustomerRealm customerRealm=new CustomerRealm();
DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
defaultSecurityManager.setRealm(customerRealm);
SecurityUtils.setSecurityManager(defaultSecurityManager);
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken("zhangsan", "123");
subject.login(token);
System.out.println(subject.getPrincipal() + "是否驗證成功" + subject.isAuthenticated());
}
}
編譯運行可得如圖,表示shiro使用了我們自定義的Realm
4. 重寫doGetAuthorizationInfo方法表示我們需要授權的過程
代碼如下
// 模擬數據庫存放的角色名
Map<String,String> roles=new HashMap<String,String>();
{
roles.put("zhangsan","admin");
roles.put("lilsiplus","adminpro");
}
// 模擬數據庫存放的權限名
Map<String,String> permissions=new HashMap<String,String>();
{
permissions.put("admin", "update");
permissions.put("admin","delete");
permissions.put("adminpro","update");
permissions.put("adminpro", "add");
}
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
// TODO Auto-generated method stub
String userName=(String)principals.getPrimaryPrincipal();
Set<String> roles=getRolesByUsername(userName);
Set<String> permissions=getPermissionsByUserName(userName);
SimpleAuthorizationInfo simpleAuthorizationInfo=new SimpleAuthorizationInfo();
simpleAuthorizationInfo.setRoles(roles);
simpleAuthorizationInfo.setStringPermissions(permissions);
return simpleAuthorizationInfo;
}
private Set<String> getPermissionsByUserName(String userName) {
// TODO Auto-generated method stub
Set<String> permissions=new HashSet<String>();
permissions.add("delete");
permissions.add("update");
return permissions;
}
private Set<String> getRolesByUsername(String userName) {
// TODO Auto-generated method stub
Set<String> roles=new HashSet<String>();
roles.add("admin");
roles.add("test");
return roles;
}
5. 在CustomRealmTest.java文件加入測試授權的代碼
代碼如下
// 使用ArrayList存儲角色
List<String> roles = new ArrayList<String>();
roles.add("admin");
roles.add("adminplus");
roles.add("adminpro");
// 循環測試角色
for (String role : roles) {
System.out.println("當前用戶是" + subject.getPrincipal() + "\t 是否具有" + role + "角色 \t" + subject.hasRole(role));
}
// 使用arraylist存放權限組
List<String> permissions = new ArrayList<String>();
permissions.add("update");
permissions.add("delete");
permissions.add("add");
permissions.add("get");
// 循環驗證當前用戶是否具有對應的權限
for (String permission : permissions) {
System.out.println("當前用戶是" + subject.getPrincipal() + "\t 是否具有" + permission + "權限 \t"
+ subject.isPermitted(permission));
}
System.out.println(subject.isPermitted("get"));
// 登出當前用戶
subject.logout();
// 驗證當前用戶是否登出
System.out.println(subject.getPrincipal() + "是否登錄成功?" + subject.isAuthenticated());
編譯運行效果如圖,表示shiro也採用了我們自定義Realm的授權過程
6. 總結
6.1 由於自定義Realm的過程還是很簡單,幾乎也沒有踩坑的過程
6.2 自定義Realm需要繼承AuthorizingRealm類
6.3 需要在doGetAuthorizationInfo這個方法內重寫我們授權的代碼
6.4 需要在doGetAuthenticationInfo這個方法內重寫我們認證的代碼