shiro多realm配置免密碼登陸

Mr-Wanter發表於2018-12-06

情景:專案本身shiro整合用的是標準的使用者名稱、密碼驗證,現需要與第三方平臺對接,使用免密碼shiro驗證,需要多加一個免密碼驗證的realm,並保證兩個realm都可用。

Shiro.xml

1、安全管理器中新增authenticator認證策略配置

<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
    <property name="authenticator" ref="authenticator"/>
    <!--<property name="realm" ref="shiroDbRealm"></property>-->
    <!--將快取管理器,交給安全管理器-->
    <property name="cacheManager" ref="shiroSpringCacheManager"/>
    <!-- 記住密碼管理 -->
    <property name="rememberMeManager" ref="rememberMeManager"/>
    <property name="sessionManager" ref="sessionManager"/>
</bean>

2、在authenticator中配置多realm和具體的認證策略

<bean id="authenticator" class="org.apache.shiro.authc.pam.ModularRealmAuthenticator">
    <!-- 多realm配置 -->
    <property name="realms">
        <list>
            <ref bean="shiroSSORealm"/> <!-- 免密碼realm配置 -->
            <ref bean="shiroDbRealm"/>  <!-- 正常預設的realm配置 -->
        </list>
    </property>
    <!-- 配置認證策略 -->
    <property name="authenticationStrategy">
        <!-- 所有Realm皆匹配成功才算成功 -->
        <!--<bean class="org.apache.shiro.authc.pam.AllSuccessfulStrategy"></bean>-->
        <!-- 只要一個或者多個Realm認證通過就算成功 -->
         <bean class="org.apache.shiro.authc.pam.AtLeastOneSuccessfulStrategy"></bean>
        <!-- 第一個匹配成功即算匹配成功 -->
        <!-- <bean class="org.apache.shiro.authc.pam.FirstSuccessfulStrategy"></bean> -->
    </property>
</bean>

3、注入新加的realm bean 並自定義憑證匹配規則憑證匹配規則預設實現是CredentialsMatcher類的doCredentialsMatch方法,我們需要繼承該類,並重寫doCredentialsMatch方法來自定義匹配規則。

<!-- 專案自定義的ssoRealm -->
<bean id="shiroSSORealm" class="com.wf.commons.shiro.ShiroSSORealm">
    <constructor-arg name="cacheManager" ref="shiroSpringCacheManager"/>
    <constructor-arg index="1" name="matcher" ref="credentialsMatcherSSO"/>
    <!-- 啟用身份驗證快取,即快取AuthenticationInfo資訊,預設false -->
    <property name="authenticationCachingEnabled" value="true"/>
    <!-- 快取AuthenticationInfo資訊的快取名稱 -->
    <property name="authenticationCacheName" value="authenticationCache"/>
    <!-- 快取AuthorizationInfo資訊的快取名稱 -->
    <property name="authorizationCacheName" value="authorizationCache"/>
</bean>
<!-- sso免密碼登陸 -->
<bean id="credentialsMatcherSSO" class="com.wf.commons.shiro.CredentialsMatcherSSO">
</bean>
public class CredentialsMatcherSSO implements CredentialsMatcher {
    @Override
    public boolean doCredentialsMatch(AuthenticationToken authenticationToken, AuthenticationInfo authenticationInfo) {
//驗證規則寫這裡,因為ShiroSSORealm中已經對使用者名稱做了判斷,這裡不做驗證直接返回true即可
        return true;
    }
}

4、實現ShiroDbRealm類

public class ShiroSSORealm extends AuthorizingRealm {
    private static final Logger LOGGER = LogManager.getLogger(ShiroSSORealm.class);

    @Autowired private IUserService userService;
    @Autowired private IRoleService roleService;

    public ShiroSSORealm(CacheManager cacheManager, CredentialsMatcher matcher) {
        super(cacheManager,matcher);
    }

    /**
     * Shiro登入認證(原理:使用者提交 使用者名稱和密碼  
     * --- shiro 封裝令牌 
     * ---- realm 通過使用者名稱將密碼查詢返回
     * ---- shiro 自動去比較查詢出密碼和使用者輸入密碼是否一致---- 進行登陸控制 )
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(
            AuthenticationToken authcToken) throws AuthenticationException {
        LOGGER.info("Shiro開始登入認證");
//UserNameToken 是儲存使用者名稱的實體類,實現了 HostAuthenticationToken, RememberMeAuthenticationToken, Serializable介面,具體寫法可參照shiro自帶的UsernamePasswordToken來寫

        UserNameToken token = null;

        // UserNameToken,則強轉,獲取username;否則不處理。
        if(authcToken instanceof UserNameToken){
            token = (UserNameToken) authcToken;
        }else{
            return null;
        }
            UserVo uservo = new UserVo();
            uservo.setLoginName(token.getUserName());
            List<User> list = userService.selectByLoginName(uservo);
            // 賬號不存在
            if (list == null || list.isEmpty()) {
                return null;
            }
            User user = list.get(0);
            // 賬號未啟用
            if (user.getStatus() == 1) {
                return null;
            }
            // 讀取使用者的url和角色
            Map<String, Set<String>> resourceMap = roleService.selectResourceMapByUserId(user.getId());
            Set<String> urls = resourceMap.get("urls");
            Set<String> roles = resourceMap.get("roles");
            ShiroUser shiroUser = new ShiroUser(user.getId(), user.getLoginName(), user.getName(), urls);
            shiroUser.setRoles(roles);
            // 認證快取資訊,實際上密碼的引數並沒有卵用,因為我們在驗證的具體方法直接返回ture了
            return new SimpleAuthenticationInfo(shiroUser, user.getPassword().toCharArray(),
                    ShiroByteSource.of(user.getSalt()), getName());

    }

    /**
     * Shiro許可權認證
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(
            PrincipalCollection principals) {
        return null;
    }
    //這個重寫必須加,不然報令牌驗證錯誤,如果只有一個token估計不用
    @Override
    public boolean supports(AuthenticationToken var1){
        return var1 instanceof UserNameToken;
    }
}

 

相關文章