1. 程式人生 > >Shrio授權驗證詳解

Shrio授權驗證詳解

原文連結

所謂授權,就是控制你是否能訪問某個資源,比如說,你可以方位page資料夾下的jsp頁面,但是不可以訪問page資料夾下的admin資料夾下的jsp頁面。

在授權中,有三個核心元素:許可權,角色,使用者。

每個使用者可以有多個角色,每個角色也可以有多個許可權。

許可權:代表了可以執行的行為,例如對錶的讀寫之類的。

角色:代表了一組許可權

使用者:代表了一個subject,可以為使用者賦予角色,或者直接賦予許可權。

 授權驗證詳解

在Shiro中共有三種授權的驗證方式:程式設計式、註解式、JSP/GSP標籤。

程式設計授權驗證

最早的方式就是通過程式設計的方式,直接通過Subject來判斷許可權,角色等。

如果要判斷當前使用者是否有某個許可權,可以通過hasRole方法來判斷,如果有某許可權的話,則幹嘛,沒有的話則幹嘛。

複製程式碼

Subject currentUser = SecurityUtils.getSubject();

if (currentUser.hasRole("administrator")) {
    //show the admin button 
} else {
    //don't show the button?  Grey it out? 
}

複製程式碼

在Shrio中,提供了下面幾個檢測許可權的方式:

hasRole(String roleName) 如果當前使用者有這個角色,則返回true
hasRoles(List<String> roleNames) 返回一個是否有當前每個角色的結果集
hasAllRoles(Collection<String> roleNames) 如果有所有的許可權的話,則返回true

另外還有一種方式,就是呼叫checkRole方法來檢測是否有特定的許可權,如果有的話,則不會報錯,沒有的話則會丟擲AuthorizationException異常。

Subject currentUser = SecurityUtils.getSubject();

//guarantee that the current user is a bank teller and 
//therefore allowed to open the account: 
currentUser.checkRole("bankTeller");
openBankAccount();

在Shrio中,也提供了下面的幾個方法來檢測許可權:

checkRole(String roleName) 如果沒有這個許可權則報錯
checkRoles(Collection<String> roleNames) 如果沒有這其中的某個許可權都會報錯
checkRole(String... roleNames) 如果沒有這其中的某個許可權都會報錯

如果要檢測是否有某個許可權的話,則可以通過isPermitted方法來檢測。

 這個方法可以接收Permission物件也可以接收字串的許可權資訊。

複製程式碼

Permission printPermission = new PrinterPermission("laserjet4400n", "print");

Subject currentUser = SecurityUtils.getSubject();

if (currentUser.isPermitted(printPermission)) {
    //show the Print button 
} else {
    //don't show the button?  Grey it out?
}

複製程式碼

或者

複製程式碼

Subject currentUser = SecurityUtils.getSubject();

if (currentUser.isPermitted("printer:print:laserjet4400n")) {
    //show the Print button
} else {
    //don't show the button?  Grey it out? 
}

複製程式碼

在Shrio裡面提供了下面的幾個方法來檢測許可權。

isPermitted(Permission p) 如果有這個許可權的話就返回true
isPermitted(String perm) 如果有這個許可權的話就返回true
isPermitted(List<Persisson> perms) 返回每個許可權是否有的true或false的結果集
isPermitted(String ... perms) 返回每個許可權是否有的true或false的結果集
isPermittedAll(Collection<Permission> perms) 如果擁有所有的許可權則返回true
isPermittedALL(String ...Perms) 如果擁有所有的許可權則返回true

跟角色一樣,也同樣有下面的替換方式:

複製程式碼

Subject currentUser = SecurityUtils.getSubject();

//guarantee that the current user is permitted 
//to open a bank account: 
Permission p = new AccountPermission("open");
currentUser.checkPermission(p);
openBankAccount();

複製程式碼

或者

Subject currentUser = SecurityUtils.getSubject();

//guarantee that the current user is permitted 
//to open a bank account: 
currentUser.checkPermission("account:open");
openBankAccount();

也有下面幾種方法:

checkPermission(Permission p) 如果沒有這個許可權就會丟擲異常
checkPermission(String perm) 如果沒有這個許可權就會丟擲異常
checkPermissions(Collection<permission> perms) 如果沒有這些許可權中的某一個就會丟擲異常
checkPermissions(String ... perms) 如果沒有這些許可權中的某一個就會丟擲異常

註解授權驗證

Shiro的註解授權需要Java5以上的支援。

如果要想使用的話,還需要使用AOP的支援。在市面上也有很多中AOP支援,比如apache的Aspectj、Spring之類的。

RequiresAuthentication

這個註解表示要求當前使用者對這個類,介面或者方法訪問的時候,需要是已經被認證的。

@RequiresAuthentication
public void updateAccount(Account userAccount) {
    //this method will only be invoked by a
    //Subject that is guaranteed authenticated
    ...
}

RequireGuest

RequireGuest註解要求當前使用者在訪問這個類、介面或方法的時候是一個遊客,也就是說沒有登陸或者通過上演一次登陸的時候記住密碼了。

@RequiresGuest
public void signUp(User newUser) {
    //this method will only be invoked by a
    //Subject that is unknown/anonymous
    ...
}

RequiresPermissions

RequiresPermission註解要求當前使用者使用者有著許可權。

@RequiresPermissions("account:create")
public void createAccount(Account account) {
    //this method will only be invoked by a Subject
    //that is permitted to create an account
    ...
}

RequiresRoles

RequiresRoles註解要求當前使用者擁有這個角色才可以訪問,否則丟擲異常。

@RequiresRoles("administrator")
public void deleteUser(User user) {
    //this method will only be invoked by an administrator
    ...
}

RequiresUser

RequiresUser要求當前使用者必須是指定的使用者才能夠訪問這個類、介面或者方法。

@RequiresUser
public void updateAccount(Account account) {
    //this method will only be invoked by a 'user'
    //i.e. a Subject with a known identity
    ...
}

JSP/GSP標籤授權驗證

 標籤的授權驗證用來支援在web開發中的許可權控制。

授權順序 

 前面我們講了三種許可權的控制方式,接下來我們看看許可權控制的流程是什麼樣的。

下面是一張許可權控制的結構圖。

Step1:當前使用者呼叫檢測角色,許可權的方法

step2:當前使用者例項(通常是一個DelegatingSubject)通過呼叫SecurityManager的檢測角色許可權的方法,把任務轉發給SecurityManager。

Step3:SecurityManager作為一個容器,把檢測許可權的任務轉發給內部的驗證器,驗證器通常預設是一個ModularRealmAuthorizer例項,會通過Realm來檢測使用者的許可權。

Step4:每一個Realm都會被用來檢測是否支援當前的認證,支援的話則會呼叫Realm的方法來檢測是否有當前許可權。

角色與許可權配置

角色域與許可權的配置可以在INI檔案或者資料庫中配置,具體在那取決於我們具體採用哪種Realm的認證方式。

shiro.ini檔案中配置

在shiro.ini配置檔案中我們可以配置[main],[users],[roles],[urls]四個節,其中[roles]就是用來配置角色與許可權的。

例如:

複製程式碼

[roles]
# 'admin' role has all permissions, indicated by the wildcard '*'
admin = *
# The 'schwartz' role can do anything (*) with any lightsaber:
schwartz = lightsaber:*
# The 'goodguy' role is allowed to 'drive' (action) the winnebago (type) with
# license plate 'eagle5' (instance specific id)
goodguy = winnebago:drive:eagle5

複製程式碼

如果要讓某個角色擁有多個許可權,則可以用都厚隔開,指定多個許可權即可。

例項(通過ini檔案)

首先在配置檔案中配置許可權資訊,“*”是萬用字元。

複製程式碼

[users]
fuwh=123456,admin
zhangsan=123,buzhang,yuangong
lisi=12,yuangong

[roles]
admin=*
buzhang=bumen:*
yuangong=bumen:diwubu:query

複製程式碼

編寫登陸許可權認證程式:

複製程式碼

package com.fuwh.demo;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.Permission;
import org.apache.shiro.authz.permission.WildcardPermission;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.Factory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class ShiroDemo03 {
    
    private static Logger log=LoggerFactory.getLogger(ShiroDemo03.class);
    public static void main(String[] args) {
        //取得SecurityManager工廠
        Factory<SecurityManager> factory=new IniSecurityManagerFactory("classpath:shiro.ini");
        //取得SecurityManager例項
        SecurityManager securityManager=factory.getInstance();
        //將securityManager繫結到SecurityUtil
        SecurityUtils.setSecurityManager(securityManager);

        //取得當前使用者
        Subject subject=SecurityUtils.getSubject();
        
        //使用fuwh來進行登陸驗證
        if(!subject.isAuthenticated()) {
            UsernamePasswordToken token=new UsernamePasswordToken("fuwh","123456");
            try {
                subject.login(token);
                log.info(token.getPrincipal()+"登陸成功!!!");
                if(subject.hasRole("admin")) {
                    log.info(token.getPrincipal()+"有admin的角色");
                    Permission p1=new WildcardPermission("bumen:*:query");
                    if(subject.isPermitted(p1)) {
                        log.info(token.getPrincipal()+"有bumen:*:query的許可權");
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
                log.error("認證失敗...");
            }
        }
        subject.logout();
        
        log.debug("*****************************************************************");
        
        if(!subject.isAuthenticated()) {
            UsernamePasswordToken token=new UsernamePasswordToken("zhangsan","123");
            try {
                subject.login(token);
                log.info(token.getPrincipal()+"登陸成功!!!");
                if(subject.hasRole("yuangong")) {
                    log.info(token.getPrincipal()+"有yuangong的角色");
                    Permission p1=new WildcardPermission("bumen:diwubu:query");
                    if(subject.isPermitted(p1)) {
                        log.info(token.getPrincipal()+"有bumen:diwubu:query的許可權");
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
                log.error("認證失敗...");
            }
        }
        subject.logout();
        
        log.debug("*****************************************************************");
        
        if(!subject.isAuthenticated()) {
            UsernamePasswordToken token=new UsernamePasswordToken("lisi","12");
            try {
                subject.login(token);
                log.info(token.getPrincipal()+"登陸成功!!!");
                if(subject.hasRole("yuangong")) {
                    log.info(token.getPrincipal()+"有yuangong的角色");
                    Permission p1=new WildcardPermission("bumen:diwubu:update");
                    if(subject.isPermitted(p1)) {
                        log.info(token.getPrincipal()+"有bumen:diwubu:update的許可權");
                    }else {
                        log.info(token.getPrincipal()+"沒有bumen:diwubu:update的許可權");
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
                log.error("認證失敗...");
            }
        }
        subject.logout();
    }
}

複製程式碼

執行後,輸出結果:

複製程式碼

2017-08-27 14:08:36,089 [main] INFO  [org.apache.shiro.session.mgt.AbstractValidatingSessionManager] - Enabling session validation scheduler...
2017-08-27 14:08:36,640 [main] INFO  [com.fuwh.demo.ShiroDemo03] - fuwh登陸成功!!!
2017-08-27 14:08:36,640 [main] INFO  [com.fuwh.demo.ShiroDemo03] - fuwh有admin的角色
2017-08-27 14:08:36,641 [main] INFO  [com.fuwh.demo.ShiroDemo03] - fuwh有bumen:*:query的許可權
2017-08-27 14:08:36,643 [main] INFO  [com.fuwh.demo.ShiroDemo03] - zhangsan登陸成功!!!
2017-08-27 14:08:36,643 [main] INFO  [com.fuwh.demo.ShiroDemo03] - zhangsan有yuangong的角色
2017-08-27 14:08:36,643 [main] INFO  [com.fuwh.demo.ShiroDemo03] - zhangsan有bumen:diwubu:query的許可權
2017-08-27 14:08:36,644 [main] INFO  [com.fuwh.demo.ShiroDemo03] - lisi登陸成功!!!
2017-08-27 14:08:36,644 [main] INFO  [com.fuwh.demo.ShiroDemo03] - lisi有yuangong的角色
2017-08-27 14:08:36,644 [main] INFO  [com.fuwh.demo.ShiroDemo03] - lisi沒有bumen:diwubu:update的許可權

複製程式碼

需要解釋一下的是,如果某個角色的許可權是"*",則代表擁有所有的許可權。而如果只想讓使用者擁有某個部門的員工的所有許可權的話怎麼辦呢?

在Shrio中支援分層的許可權寫法,例如:emp=bumen:yuangong:*,這樣的分層則更容易的對許可權來進行控制,

如果角色的許可權為emp=bumen:update,則等價於emp=bumen:*:updae。

同時,emp=bumen:yuangong也等價於emp=bumen:yuangong:*。

通過Shiro自帶的JdbcRealm

在JdbcReal中,預設的角色與許可權的查詢是通過靜態變數DEFAULT_USER_ROLES_QUERY和DEFAULT_PERMISSIONS_QUERY中定義的sql語句來查詢的。

DEFAULT_USER_ROLES_QUERY = "select role_name from user_roles where username = ?";

DEFAULT_PERMISSIONS_QUERY = "select permission from roles_permissions where role_name = ?";

並分別把他們的值賦給userRolesQuery和permissionsQuery。

所以預設情況下是從user_roles表中去查詢角色資訊,從roles_permissions表中去查詢許可權資訊。

如果需要自定義表名,列名的話,可以通過在配置檔案中覆寫這兩個sql語句。

例項

首先建立資料庫如下:

複製程式碼

USE `db_shiro`;

DROP TABLE IF EXISTS `users`;

CREATE TABLE `users` (
  `id` int(4) NOT NULL AUTO_INCREMENT,
  `username` varchar(20) DEFAULT NULL,
  `password` varchar(100) DEFAULT NULL,
  UNIQUE KEY `id` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;

insert  into `users`(`id`,`username`,`password`) values (1,'fuwh','123456'),(2,'zhangsan','123'),(3,'lisi','12');

DROP TABLE IF EXISTS `user_roles`;

CREATE TABLE `user_roles` (
  `username` varchar(20) NOT NULL,
  `role_name` varchar(20) NOT NULL,
  `role_desc` varchar(100) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

insert  into `user_roles`(`username`,`role_name`,`role_desc`) values ('fuwh','admin','管理員'),('zhangsan','buzhang','部長'),('lisi','yuangong','員工'),('zhangsan','yuangong','員工');

DROP TABLE IF EXISTS `roles_permissions`;

CREATE TABLE `roles_permissions` (
  `role_name` varchar(20) NOT NULL,
  `permission` varchar(20) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

insert  into `roles_permissions`(`role_name`,`permission`) values ('admin','*'),('buzhang','bumen:*'),('yuangong','bumen:diwubu:query');

複製程式碼

編寫配置檔案:

複製程式碼

[main]
dataSource=com.mchange.v2.c3p0.ComboPooledDataSource
dataSource.driverClass=com.mysql.jdbc.Driver
dataSource.jdbcUrl=jdbc:mysql://localhost:3306/db_shiro
dataSource.user=root
dataSource.password=rootadmin

jdbcRealm=org.apache.shiro.realm.jdbc.JdbcRealm
jdbcRealm.dataSource=$dataSource
securityManager.realms=$jdbcRealm

複製程式碼

編寫授權程式碼:

複製程式碼

package com.fuwh.demo;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.Permission;
import org.apache.shiro.authz.permission.WildcardPermission;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.Factory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class ShiroDemoJdbc03 {
    
    private static Logger log=LoggerFactory.getLogger(ShiroDemoJdbc03.class);
    public static void main(String[] args) {
        //取得SecurityManager工廠
        Factory<SecurityManager> factory=new IniSecurityManagerFactory("classpath:shiro_jdbc.ini");
        //取得SecurityManager例項
        SecurityManager securityManager=factory.getInstance();
        //將securityManager繫結到SecurityUtil
        SecurityUtils.setSecurityManager(securityManager);

        /*    至此為止,簡單的從mysql資料庫讀取realm資訊的shiro環境就配置好了    */
        
        //取得當前使用者
        Subject subject=SecurityUtils.getSubject();
        
        //使用fuwh來進行登陸驗證
                if(!subject.isAuthenticated()) {
                    UsernamePasswordToken token=new UsernamePasswordToken("fuwh","123456");
                    try {
                        subject.login(token);
                        log.info(token.getPrincipal()+"登陸成功!!!");
                        if(subject.hasRole("admin")) {
                            log.info(token.getPrincipal()+"有admin的角色");
                            Permission p1=new WildcardPermission("bumen:*:query");
                            if(subject.isPermitted(p1)) {
                                log.info(token.getPrincipal()+"有bumen:*:query的許可權");
                            }
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                        log.error("認證失敗...");
                    }
                }
                subject.logout();
                
                log.debug("*****************************************************************");
                
                if(!subject.isAuthenticated()) {
                    UsernamePasswordToken token=new UsernamePasswordToken("zhangsan","123");
                    try {
                        subject.login(token);
                        log.info(token.getPrincipal()+"登陸成功!!!");
                        if(subject.hasRole("yuangong")) {
                            log.info(token.getPrincipal()+"有yuangong的角色");
                            Permission p1=new WildcardPermission("bumen:diwubu:query");
                            if(subject.isPermitted(p1)) {
                                log.info(token.getPrincipal()+"有bumen:diwubu:query的許可權");
                            }
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                        log.error("認證失敗...");
                    }
                }
                subject.logout();
                
                log.debug("*****************************************************************");
                
                if(!subject.isAuthenticated()) {
                    UsernamePasswordToken token=new UsernamePasswordToken("lisi","12");
                    try {
                        subject.login(token);
                        log.info(token.getPrincipal()+"登陸成功!!!");
                        if(subject.hasRole("yuangong")) {
                            log.info(token.getPrincipal()+"有yuangong的角色");
                            Permission p1=new WildcardPermission("bumen:diwubu:update");
                            if(subject.isPermitted(p1)) {
                                log.info(token.getPrincipal()+"有bumen:diwubu:update的許可權");
                            }else {
                                log.info(token.getPrincipal()+"沒有bumen:diwubu:update的許可權");
                            }
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                        log.error("認證失敗...");
                    }
                }
                subject.logout();
    }
}

複製程式碼

執行結果:

複製程式碼

2017-08-27 14:08:36,089 [main] INFO  [org.apache.shiro.session.mgt.AbstractValidatingSessionManager] - Enabling session validation scheduler...
2017-08-27 14:08:36,640 [main] INFO  [com.fuwh.demo.ShiroDemo03] - fuwh登陸成功!!!
2017-08-27 14:08:36,640 [main] INFO  [com.fuwh.demo.ShiroDemo03] - fuwh有admin的角色
2017-08-27 14:08:36,641 [main] INFO  [com.fuwh.demo.ShiroDemo03] - fuwh有bumen:*:query的許可權
2017-08-27 14:08:36,643 [main] INFO  [com.fuwh.demo.ShiroDemo03] - zhangsan登陸成功!!!
2017-08-27 14:08:36,643 [main] INFO  [com.fuwh.demo.ShiroDemo03] - zhangsan有yuangong的角色
2017-08-27 14:08:36,643 [main] INFO  [com.fuwh.demo.ShiroDemo03] - zhangsan有bumen:diwubu:query的許可權
2017-08-27 14:08:36,644 [main] INFO  [com.fuwh.demo.ShiroDemo03] - lisi登陸成功!!!
2017-08-27 14:08:36,644 [main] INFO  [com.fuwh.demo.ShiroDemo03] - lisi有yuangong的角色
2017-08-27 14:08:36,644 [main] INFO  [com.fuwh.demo.ShiroDemo03] - lisi沒有bumen:diwubu:update的許可權

複製程式碼

通過自定義的MyJdbcRealm實現

建立資料庫:

複製程式碼

USE `db_shiro`;


DROP TABLE IF EXISTS `members`;

CREATE TABLE `members` (
  `id` INT(4) NOT NULL AUTO_INCREMENT,
  `membername` VARCHAR(20) DEFAULT NULL,
  `password` VARCHAR(100) DEFAULT NULL,
  UNIQUE KEY `id` (`id`)
) ENGINE=INNODB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;


INSERT  INTO `members`(`id`,`membername`,`password`) VALUES (1,'fuwh','123456'),(2,'zhangsan','123'),(3,'lisi','12');


DROP TABLE IF EXISTS `roles_permissions`;

CREATE TABLE `roles_permissions` (
  `role_name` VARCHAR(20) NOT NULL,
  `permission` VARCHAR(20) NOT NULL
) ENGINE=INNODB DEFAULT CHARSET=utf8;


INSERT  INTO `roles_permissions`(`role_name`,`permission`) VALUES ('admin','*'),('buzhang','bumen:*'),('yuangong','bumen:diwubu:query');

DROP TABLE IF EXISTS `member_roles`;

CREATE TABLE `member_roles` (
  `membername` VARCHAR(20) NOT NULL,
  `role_name` VARCHAR(20) NOT NULL,
  `role_desc` VARCHAR(100) DEFAULT NULL
) ENGINE=INNODB DEFAULT CHARSET=utf8;


INSERT  INTO `member_roles`(`membername`,`role_name`,`role_desc`) VALUES ('fuwh','admin','管理員'),('zhangsan','buzhang','部長'),('lisi','yuangong','員工'),('zhangsan','yuangong','員工');

複製程式碼

編寫MyJdbcRealm

複製程式碼

package com.fuwh.realm;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.LinkedHashSet;
import java.util.Set;

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.fuwh.util.DbUtil;

public class MyJdbcRealm extends AuthorizingRealm{

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        // TODO Auto-generated method stub
        SimpleAuthorizationInfo info=new SimpleAuthorizationInfo();
        Set<String> roleNames=new LinkedHashSet<String>();
        Connection conn=DbUtil.getConnection();
        String sql="select role_name from member_roles where membername=?";
        try {
            PreparedStatement ps=conn.prepareStatement(sql);
            ps.setString(1, principals.toString());
            ResultSet rs=ps.executeQuery();
            while(rs.next()) {
                roleNames.add(rs.getString(1));
            }
            rs.close();
            info.setRoles(roleNames);
            try {
                Set<String> permissions=getPermissions(conn,roleNames);
                info.setStringPermissions(permissions);
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            ps.close();
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return info;
    }

    
    protected Set<String> getPermissions(Connection conn,Set<String> roleNames) throws Exception{
        Set<String> permissions=new LinkedHashSet<String>();
        String sql="select permission from roles_permissions where role_name=?";
        PreparedStatement ps=conn.prepareStatement(sql);
        for (String roleName : roleNames) {
            ps.setString(1,roleName);
            ResultSet rs=ps.executeQuery();
            while(rs.next()) {
                permissions.add(rs.getString("permission"));
            }
            rs.close();
        }
        ps.close();
        return permissions;
    }
    
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        // TODO Auto-generated method stub
        Connection conn=DbUtil.getConnection();
        String sql="select * from members where userName=?";
        try {
            PreparedStatement ps=conn.prepareStatement(sql);
            ps.setString(1, token.getPrincipal().toString());
            ResultSet rs=ps.executeQuery();
            while(rs.next()) {
                AuthenticationInfo info=new SimpleAuthenticationInfo(rs.getString("userName"),rs.getString("pass"),"salt");
                return info;
            }
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return null;
    }
    
}

複製程式碼

編寫配置檔案:

[main]myJdbcRealm=com.fuwh.realm.MyJdbcRealmsecurityManager.realms=$myJdbcRealm

 編寫許可權認證程式碼:

複製程式碼

package com.fuwh.demo;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.Permission;
import org.apache.shiro.authz.permission.WildcardPermission;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.Factory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class ShiroDemoMyJdbc03 {
    
    private static Logger log=LoggerFactory.getLogger(ShiroDemoMyJdbc03.class);
    public static void main(String[] args) {
        //取得SecurityManager工廠
        Factory<SecurityManager> factory=new IniSecurityManagerFactory("classpath:shiro_my_jdbc.ini");
        //取得SecurityManager例項
        SecurityManager securityManager=factory.getInstance();
        //將securityManager繫結到SecurityUtil
        SecurityUtils.setSecurityManager(securityManager);

        /*    至此為止,簡單的從mysql資料庫讀取realm資訊的shiro環境就配置好了    */
        
        //取得當前使用者
        Subject subject=SecurityUtils.getSubject();
        
        //使用fuwh來進行登陸驗證
                if(!subject.isAuthenticated()) {
                    UsernamePasswordToken token=new UsernamePasswordToken("fuwh","123456");
                    try {
                        subject.login(token);
                        log.info(token.getPrincipal()+"登陸成功!!!");
                        if(subject.hasRole("admin")) {
                            log.info(token.getPrincipal()+"有admin的角色");
                            Permission p1=new WildcardPermission("bumen:*:query");
                            if(subject.isPermitted(p1)) {
                                log.info(token.getPrincipal()+"有bumen:*:query的許可權");
                            }
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                        log.error("認證失敗...");
                    }
                }
                subject.logout();
                
                log.debug("*****************************************************************");
                
                if(!subject.isAuthenticated()) {
                    UsernamePasswordToken token=new UsernamePasswordToken("zhangsan","123");
                    try {
                        subject.login(token);
                        log.info(token.getPrincipal()+"登陸成功!!!");
                        if(subject.hasRole("yuangong")) {
                            log.info(token.getPrincipal()+"有yuangong的角色");
                            Permission p1=new WildcardPermission("bumen:diwubu:query");
                            if(subject.isPermitted(p1)) {
                                log.info(token.getPrincipal()+"有bumen:diwubu:query的許可權");
                            }
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                        log.error("認證失敗...");
                    }
                }
                subject.logout();
                
                log.debug("*****************************************************************");
                
                if(!subject.isAuthenticated()) {
                    UsernamePasswordToken token=new UsernamePasswordToken("lisi","12");
                    try {
                        subject.login(token);
                        log.info(token.getPrincipal()+"登陸成功!!!");
                        if(subject.hasRole("yuangong")) {
                            log.info(token.getPrincipal()+"有yuangong的角色");
                            Permission p1=new WildcardPermission("bumen:diwubu:update");
                            if(subject.isPermitted(p1)) {
                                log.info(token.getPrincipal()+"有bumen:diwubu:update的許可權");
                            }else {
                                log.info(token.getPrincipal()+"沒有bumen:diwubu:update的許可權");
                            }
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                        log.error("認證失敗...");
                    }
                }
                subject.logout();
    }
}

複製程式碼