Shrio認證詳解+自定義Realm


Authentication(身份認證)是Shiro權限控制的第一步,用來告訴系統你就是你。

在提交認證的時候,我們需要給系統提交兩個信息:

Principals:是一個表示用戶的唯一屬性,可以是用戶名,郵箱之類的。

Credentials:是證明用戶身份的證書,可以是密碼或者指紋之類的。

認證主要分為三步:

1、收集認證信息

2、提交認證信息

3、如果認證成功,則允許訪問,否則就拒絕訪問或者重試。

收集認證信息

入門的例子中,使用了一個UsernamePasswordToken來收集用戶的用戶名和密碼,用來登陸。

這個類支持最簡單的用戶名和密碼登陸。實現了org.apache.shiro.authc.AuthenticationToken接口。

AuthenticationToken接口是認證系統的基礎,只有getCredentials(),getPrincipal()兩個方法用來獲取基本的認證信息。

HostAuthenticationToken和RememberMeAuthenticationToken是它的兩個子接口。

HostAuthenticationToken只有一個getHost()方法用來獲取請求的地址信息。

RememberMeAuthenticationToken只有一個isRememberMe()方法用來標記用戶是否需要記住我。

然后還有兩個子類UsernamePasswordToken和CasToken提供了基本的實現。其中CasToken已經被廢棄了。

例:

//Example using most common scenario of username/password pair:
UsernamePasswordToken token = new UsernamePasswordToken(username, password);
//"Remember Me" built-in: 
token.setRememberMe(true);

 

提交認證信息:

收集好認證信息之后,保存為AuthenticationToken的一個實例,我們需要提交這個認證信息來進行認證。

進行認證前,我們首先需要獲取當前用戶(Subject)。然后調用login方法來進行登陸。

例:

Subject currentUser = SecurityUtils.getSubject();
currentUser.login(token);

處理結果:

如果登陸成功的話,則不會有什么異常,此時如果調用isAuthenticated()方法,則會返回true。

如果登陸失敗的話,則被拋出異常,在SHiro中,提供了很多異常類,可以用來捕捉具體的異常。

例子:

try {
    currentUser.login(token);
} catch ( UnknownAccountException uae ) { ...
} catch ( IncorrectCredentialsException ice ) { ...
} catch ( LockedAccountException lae ) { ...
} catch ( ExcessiveAttemptsException eae ) { ...
} ... catch your own ...
} catch ( AuthenticationException ae ) {
    //unexpected error?
}

//No problems, continue on as expected...

可以看到,前面出現了Remembered和Authenticated。那這兩種有什么區別呢?

需要注意的是,這是兩種互斥的情況,當我們在登陸的時候,登陸成功之后,我們Authenticated返回的是true。

選擇Remeber me的時候,我們下次可以不登陸直接訪問,而我們下次登陸之后,Remembered返回的是true,但是Authenticated返回的是false。

在登陸之后,我們可以可以用logout()方法來注銷。這時候用戶的信息都會被清空,包括保存在Cookie中的RemeberMe信息還有session也會被無效。

上面我們就簡單的講述了一下在代碼中實現登陸驗證的流程。具體實例可以參考入門的例子。

那么,在Shrio內部是怎么樣的一個認證流程呢?大概可以用下圖來概括:

第一步:在代碼中調用login方法,傳遞構造好的AuthenticationToken實例。

第二步:通過一個DelegatingSubject來分發認證請求給SecurityManager

第三步:SecurityManager容器會把接收到的token簡單的轉發給它內部的認證器實例通過調用認證器的authenticate(token)方法。

這通常是一個ModularRealmAuthenticator實例,用來支持多個Realm。

第四步:如果有定義多個Realm則ModularRealmAuthenticator會初始化一個支持多個Realm的認證器,通過配置的AuthenticationStrategy。

第五步:每一個配置的Realm都會被檢測是否支持提交的AuthenticationToken,如果支持的話就會調用getAuthenticationInfo方法,從Realm中獲取數據來跟提交的token進行驗證。

驗證器

在SecurityManager中,默認使用ModularRealmAuthenticator實例,它不僅僅支持單Realm還支持多個Realm。

如果實在單個Realm的情況下,ModualrRealmAuthenticator會直接調用這個Realm來嘗試驗證。

如果我們需要定義自己的驗證器的話,可以通過在配置文件的[main]中如下定義:

[main]
...
authenticator = com.foo.bar.CustomAuthenticator
securityManager.authenticator = $authenticator

驗證策略

如果是只有一個Realms的時候,則不需要驗證策略。

如果是有兩個以上的Realm的時候,ModularRealmAuthenticator依賴於AuthenticationStrategy組件來決定認證成功或者失敗的條件,

比如是一個成功就成功還是要都成功才是成功之類的。。。。

在Shiro里面已經有三個認證策略的實現

AtLeastOneSuccessfulStrategy:只要有一個或一個以上的認證成功就表示認證成功

FirstSuccessfulStrategy;只有第一個認證成功的時候才表示認證成功

AllSuccessfulStrategy:只有所有的都認證成功的時候才表示認證成功。

在ModularRealmAuthenticator默認使用AtLeastOneSuccessfulStrategy的驗證策略。當然也可以通過下面的方式定義其他的驗證策略。

[main]
...
authcStrategy = org.apache.shiro.authc.pam.FirstSuccessfulStrategy
securityManager.authenticator.authenticationStrategy = $authcStrategy
...

Realm認證順序

在定義了多個Realm的時候,如果有多個Realm支持當前的AuthenticationToken,則會依次調用Realm的getAuthenticationInfo方法。

調用的順序分為兩種:

隱式的:

如果在SecurityManager中定義了如下的幾個Realm,則會按照他們定義的順序去調用。

blahRealm = com.company.blah.Realm
...
fooRealm = com.company.foo.Realm
...
barRealm = com.company.another.Realm

此時的效果就等於下面的語句。

securityManager.realms = $blahRealm, $fooRealm, $barRealm、

顯示的:

就如上面的一樣,如果在securityManager.realms中配置的時候,改變realm的配置順序,則會按照這個配置順序來調用,這就是顯示的配置。

blahRealm = com.company.blah.Realm
...
fooRealm = com.company.foo.Realm
...
barRealm = com.company.another.Realm
securityManager.realms = $fooRealm, $barRealm, $blahRealm
...

域認證

前面說了下Realm的認證策略和認證順序,那么,在Realm認證的時候,究竟發生什么事情了呢?

supporting AuthenticationTokens

在Realm被用來嘗試認證登陸的時候首先會調用supports方法,來檢測是否能解析這個AuthenticationToken,決定是否進行認證。

Handing supported AuthenticationTokens

如果這個realm支持提交的AuthenticationTokens的話,解析器會調用Realm的getAuthenticationINfo(token)方法,來嘗試認證,

這個方法大概做了下面這些事情:

1、檢測token中的唯一用戶標識

2、基於唯一標識 去數據源中查找

3、確保提供的證書跟數據源中保存的一樣

4、如果證書一樣,就封裝一個AuthenticationINfo實例返回

5、如果證書不匹配,則拋出一個AuthenticationException異常

下面,我們來看看Shrio提供的Realm的類結構:

org.apache.shiro.realm.Realm(I):base
  org.apache.shiro.realm.CachingRealm(Abstract):提供緩存支持
    org.apache.shiro.realm.AuthenticatingRealm(Abstract):提供認證支持
      org.apache.shiro.realm.AuthorizingRealm(Abstract):提供授權支持
        org.apache.shiro.realm.SimpleAccountRealm(C):簡單的用戶名密碼支持
          org.apache.shiro.realm.text.TextConfigurationRealm(C):支持Text文件的簡單用戶名密碼支持
            org.apache.shiro.realm.text.IniRealm(C):通過INI文件的簡單用戶名密碼支持(默認使用這個)
            org.apache.shiro.realm.text.PropertiesRealm(C):支持屬性文件的簡單用戶名密碼支持
        org.apache.shiro.realm.jdbc.JdbcRealm(C):支持通過JDBC認證

 在系統默認的情況下,系統使用的是IniRealm這個實現,可以從INI配置文件的[users]和[roles]兩個節中讀取用戶信息和權限信息。

如果我們需要定義自己的Realm實現的話,一般都是繼承AuthorizingRealm。

稍候,我們將簡單介紹下如果從db中來實現認證。

證書匹配

前面我們說過,Realm需要去匹配用戶提交的證書跟數據源中存儲的證書是否匹配,如果匹配的話就認為是認證成功。

在獲得用戶唯一標識后,系統回去Realm會去檢索用戶的證書,然后通過CredentialsMatcher來檢測證書是否匹配。

Shrio中也提供了一些證書的匹配器可以直接拿來使用,使用下面的方法變更默認的匹配器:

[main]
...
customMatcher = com.company.shiro.realm.CustomCredentialsMatcher
myRealm = com.company.shiro.realm.MyRealm
myRealm.credentialsMatcher = $customMatcher
...

Simple Equality Check

默認情況下所有提供的Realm實現都是使用SimpleCredentialsMatcher來檢測證書是否匹配。

不過一般情況下都不需要變更,因為默認的就足夠了。

Hashing Credentials

相比使用原始的數據存儲起來,拿來匹配,我們更願意將證書加密進行存儲來進行匹配。那么如何使用呢?

在Shiro中提供了幾個HashedCredentialsMatcher的子類,用來實現這個功能。包括MD5、SHA-256等等的加密方式。

我們可以通過下面的配置方式:

[main]
...
credentialsMatcher = org.apache.shiro.authc.credential.Sha256CredentialsMatcher
# base64 encoding, not hex in this example:
credentialsMatcher.storedCredentialsHexEncoded = false
credentialsMatcher.hashIterations = 1024
# This next property is only needed in Shiro 1.0\.  Remove it in 1.1 and later:
credentialsMatcher.hashSalted = true

...
myRealm = com.company.....
myRealm.credentialsMatcher = $credentialsMatcher
...

需要注意的是,這種情況下在Realm的實現中需要返回一個SaltedAuthenticationInfo,而不是普通的AuthenticationInfo,因為在用戶提交認證的時候,需要獲取相同的salt來進行加密,進行匹配認證。

那這個salt(鹽)是用來干嘛的呢?

這是因為在進行MD5之類加密的時候,還是可以進行破解的,但是如果加入一個變量來進行加密之后,就基本上是無法破解了(不知道這個SALT的情況下)。

 

下面我們就做一個通過JDBC來認證的登陸認證程序。點此看源碼

首先我們需要一個用戶表,腳本如下:

CREATE DATABASE `db_shiro` 

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=2 DEFAULT CHARSET=utf8;

insert  into `users`(`id`,`username`,`password`) values (1,'fuwh','123456');

我們需要定義一個shiro_jdbc.ini文件如下

[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

;this is comment read from mysql
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.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 ShiroDemo02 {
    
    private static Logger log=LoggerFactory.getLogger(ShiroDemo02.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 currentUser=SecurityUtils.getSubject();
        
        //使用shiro來進行登陸驗證
        if(!currentUser.isAuthenticated()) {
            UsernamePasswordToken token=new UsernamePasswordToken("fuwh","123456");
            try {
                currentUser.login(token);
                log.info("登陸成功!!!");
            } catch (Exception e) {
                e.printStackTrace();
                log.error("認證失敗...");
            }
        }
        
        currentUser.logout();
    }
}

執行結果:

2017-08-26 15:16:03,357 [main] INFO  [com.mchange.v2.log.MLog] - MLog clients using log4j logging.
2017-08-26 15:16:04,107 [main] INFO  [com.mchange.v2.c3p0.C3P0Registry] - Initializing c3p0-0.9.1.2 [built 21-May-2007 15:04:56; debug? true; trace: 10]
2017-08-26 15:16:04,436 [main] INFO  [org.apache.shiro.config.IniSecurityManagerFactory] - Realms have been explicitly set on the SecurityManager instance - auto-setting of realms will not occur.
2017-08-26 15:16:04,560 [main] INFO  [com.mchange.v2.c3p0.impl.AbstractPoolBackedDataSource] - Initializing c3p0 pool... com.mchange.v2.c3p0.ComboPooledDataSource [ acquireIncrement -> 3, acquireRetryAttempts -> 30, acquireRetryDelay -> 1000, autoCommitOnClose -> false, automaticTestTable -> null, breakAfterAcquireFailure -> false, checkoutTimeout -> 0, connectionCustomizerClassName -> null, connectionTesterClassName -> com.mchange.v2.c3p0.impl.DefaultConnectionTester, dataSourceName -> 1hgetj59q83i1dm1es8ork|67f89fa3, debugUnreturnedConnectionStackTraces -> false, description -> null, driverClass -> com.mysql.jdbc.Driver, factoryClassLocation -> null, forceIgnoreUnresolvedTransactions -> false, identityToken -> 1hgetj59q83i1dm1es8ork|67f89fa3, idleConnectionTestPeriod -> 0, initialPoolSize -> 3, jdbcUrl -> jdbc:mysql://localhost:3306/db_shiro, maxAdministrativeTaskTime -> 0, maxConnectionAge -> 0, maxIdleTime -> 0, maxIdleTimeExcessConnections -> 0, maxPoolSize -> 15, maxStatements -> 0, maxStatementsPerConnection -> 0, minPoolSize -> 3, numHelperThreads -> 3, numThreadsAwaitingCheckoutDefaultUser -> 0, preferredTestQuery -> null, properties -> {user=******, password=******}, propertyCycle -> 0, testConnectionOnCheckin -> false, testConnectionOnCheckout -> false, unreturnedConnectionTimeout -> 0, usesTraditionalReflectiveProxies -> false ]
2017-08-26 15:16:05,040 [main] INFO  [org.apache.shiro.session.mgt.AbstractValidatingSessionManager] - Enabling session validation scheduler...
2017-08-26 15:16:05,056 [main] INFO  [com.fuwh.demo.ShiroDemo02] - 登陸成功!!!

此時,已經可以從表中去驗證登陸了。那處理流程又是什么樣的呢?

首先我們使用shiro_jdbc.ini來初始化了SecurityManager,在配置文件中,我們定義了連接池信息,還有jdbcRealm,同時在SecurityManager中指定了realm為定義的JjdbcRealm,這時候,其實shiro使用的SecurityManager是一個RealmSecurityManager的實例。而當我們登陸的時候,則會通過配置的jdbcRealm來從數據庫中取得用戶信息來進行認證。那是怎么取得呢?我們明明沒有寫sql什么的。

其實,看org.apache.shiro.realm.jdbc.JdbcRealm的源碼可以看到,在這個類里面定義了很多的靜態sql變量,點此查看點此查看sql內容

其中比較重要的是AuthenticationQuery這個字段,默認情況下它的值是等於Default_Authentication_query。

Default_Authentication_Query="select password from users where username=?";

所以在默認情況下,它會從users這個表中通過username這個key來查找password。從而拿來跟我們提交的密碼來進行匹配驗證。

如果我們不想使用默認的數據庫,默認的表名,默認的列名的話,也可以通過在配置文件中重寫AuthenticationQuery的值來個性化sql文。

首先修改新建一個表members:

USE `db_shiro`;

DROP TABLE IF EXISTS `members`;

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


INSERT  INTO `members`(`id`,`userName`,`pass`) VALUES (1,'fuwh','123');

然后修改shiro_jdbc_sql.ini配置文件:

[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

;this is comment read from mysql
jdbcRealm=org.apache.shiro.realm.jdbc.JdbcRealm
jdbcRealm.dataSource=$dataSource
jdbcRealm.authenticationQuery=select pass from members where userName=? 
securityManager.realms=$jdbcRealm

修改認證程序的配置文件:

package com.fuwh.demo;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
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 ShiroDemoSql02 {
    
    private static Logger log=LoggerFactory.getLogger(ShiroDemoSql02.class);
    public static void main(String[] args) {
        //取得SecurityManager工廠
        Factory<SecurityManager> factory=new IniSecurityManagerFactory("classpath:shiro_jdbc_sql.ini");
        //取得SecurityManager實例
        SecurityManager securityManager=factory.getInstance();
        //將securityManager綁定到SecurityUtil
        SecurityUtils.setSecurityManager(securityManager);

        /*    至此為止,簡單的從mysql數據庫讀取realm信息的shiro環境就配置好了    */
        
        //取得當前用戶
        Subject currentUser=SecurityUtils.getSubject();
        
        //使用shiro來進行登陸驗證
        if(!currentUser.isAuthenticated()) {
            UsernamePasswordToken token=new UsernamePasswordToken("fuwh","123");
            try {
                currentUser.login(token);
                log.info("登陸成功!!!");
            } catch (Exception e) {
                e.printStackTrace();
                log.error("認證失敗...");
            }
        }
        
        currentUser.logout();
    }
}

后面我們會講到角色認證也是同樣的道理。

自定義Realm

上面我們使用的是Shiro提供的默認的Realm,下面我們自定義一個從數據庫中讀取信息的Realm,通過繼承AuthorizingRealm。

package com.fuwh.realm;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

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.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
        return null;
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        // TODO Auto-generated method stub
        Connection conn=DbUtil.getConnection();
        String sql="select * from members2 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("password"),"salt");
                return info;
            }
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        
        return null;
    }
    
}

修改配置文件

[main]
myJdbcRealm=com.fuwh.realm.MyJdbcRealm
securityManager.realms=$myJdbcRealm

編寫登陸類:

package com.fuwh.demo;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
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 ShiroDemoMySql02 {
    
    private static Logger log=LoggerFactory.getLogger(ShiroDemoMySql02.class);
    public static void main(String[] args) {
        //取得SecurityManager工廠
        Factory<SecurityManager> factory=new IniSecurityManagerFactory("classpath:shiro_jdbc_my_sql.ini");
        //取得SecurityManager實例
        SecurityManager securityManager=factory.getInstance();
        //將securityManager綁定到SecurityUtil
        SecurityUtils.setSecurityManager(securityManager);

        /*    至此為止,簡單的從mysql數據庫讀取realm信息的shiro環境就配置好了    */
        
        //取得當前用戶
        Subject currentUser=SecurityUtils.getSubject();
        
        //使用shiro來進行登陸驗證
        if(!currentUser.isAuthenticated()) {
            UsernamePasswordToken token=new UsernamePasswordToken("fuwh","123");
            try {
                currentUser.login(token);
                log.info("登陸成功!!!");
            } catch (Exception e) {
                e.printStackTrace();
                log.error("認證失敗...");
            }
        }
        
        currentUser.logout();
    }
}

 

 那如果我們定義了多個Realm呢?

在編寫一個Realm類:

package com.fuwh.realm;

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.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;

public class MyJdbcRealm2 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    new SimpleAuthenticationInfo(token.getPrincipal(),"1234","salt");
    } 
}

修改shiro_jdbc_my_sql_2.ini配置文件:

[main]
myJdbcRealm=com.fuwh.realm.MyJdbcRealm
myJdbcRealm2=com.fuwh.realm.MyJdbcRealm2
authStrategy=org.apache.shiro.authc.pam.AtLeastOneSuccessfulStrategy
securityManager.realms=$myJdbcRealm,$myJdbcRealm2
securityManager.authenticator.authenticationStrategy=$authStrategy

修改登陸類:

package com.fuwh.demo;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
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 ShiroDemoMySql02_2 {
    
    private static Logger log=LoggerFactory.getLogger(ShiroDemoMySql02_2.class);
    public static void main(String[] args) {
        //取得SecurityManager工廠
        Factory<SecurityManager> factory=new IniSecurityManagerFactory("classpath:shiro_jdbc_my_sql_2.ini");
        //取得SecurityManager實例
        SecurityManager securityManager=factory.getInstance();
        //將securityManager綁定到SecurityUtil
        SecurityUtils.setSecurityManager(securityManager);

        /*    至此為止,簡單的從mysql數據庫讀取realm信息的shiro環境就配置好了    */
        
        //取得當前用戶
        Subject currentUser=SecurityUtils.getSubject();
        
        //使用shiro來進行登陸驗證
        if(!currentUser.isAuthenticated()) {
            UsernamePasswordToken token=new UsernamePasswordToken("fuwh","123");
            try {
                currentUser.login(token);
                log.info("登陸成功!!!");
            } catch (Exception e) {
                e.printStackTrace();
                log.error("認證失敗...");
            }
        }
        
        currentUser.logout();
    }
}

上面的例子中使用的認證策略是只有一個成功就認為是成功。

在Shiro中還提供了下面幾個策略:

FirstSuccessfulStrategy:只有第一個認證成功的信息會被用

AllSuccessfulStrategy:只有當所有的都成功的時候才認為是認證成功。

 

源碼地址:https://github.com/oukafu/shiro


免責聲明!

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



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