1. 程式人生 > >shiro許可權驗證

shiro許可權驗證

上次介紹了shiro的一些理論知識,這次用一些程式碼來具體實現角色驗證與登入驗證
首先介紹一下使用的環境:
SpringBoot + Mybatis + Shiro
新增的類

  1. ShiroRealm 繼承了AuthorizingRealm類,實現兩個方法,分別為登入許可權驗證,以及角色許可權驗證的功能。(註釋已經很詳細了,詳細瞭解請看註釋)
import com.aim.chenapp.dao.entity.UserInfoEntity;
import com.aim.chenapp.service.UserInfoService;
import
com.fasterxml.jackson.databind.Module; import org.apache.catalina.Role; import org.apache.shiro.authc.*; 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
org.apache.shiro.util.ByteSource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import java.util.*; public class ShiroRealm extends AuthorizingRealm { private Logger logger = LoggerFactory.getLogger(ShiroRealm.class); @Autowired
private UserInfoService userInfoService; private SimpleAuthenticationInfo info = null; /** * 1.doGetAuthenticationInfo,獲取認證訊息,如果資料庫中沒有數,返回null,如果得到了正確的使用者名稱和密碼, * 返回指定型別的物件 * * 2.AuthenticationInfo 可以使用SimpleAuthenticationInfo實現類,封裝正確的使用者名稱和密碼。 * * 3.token引數 就是我們需要認證的token * @param authenticationToken * @return * @throws AuthenticationException */ //認證登入 @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { // 1.將token裝換成UsernamePasswordToken UsernamePasswordToken upToken = (UsernamePasswordToken) authenticationToken; logger.info("驗證當前Subject時獲取到token為:" + upToken.toString()); // 2.獲取使用者名稱即可 String username = upToken.getUsername(); // 3.查詢資料庫,是否查詢到使用者名稱和密碼的使用者 UserInfoEntity userInfo = userInfoService.selectByPhone(username); if(userInfo != null) { // 4.如果查詢到了,封裝查詢結果,返回給我們的呼叫 Object principal = userInfo.getPhoneNumber(); Object credentials = userInfo.getPassword(); ByteSource salt = ByteSource.Util.bytes(username); String realmName = this.getName(); info = new SimpleAuthenticationInfo(principal, credentials, salt,realmName); }else { // 5.如果沒有查詢到,丟擲一個異常 throw new AuthenticationException(); } return info; } //授權 @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { logger.info("##################執行Shiro許可權認證##################"); String username = (String) principalCollection.getPrimaryPrincipal(); UserInfoEntity user = userInfoService.selectByPhone(username); if (user != null) { //許可權資訊物件info,用來存放查出的使用者的所有的角色(role)及許可權(permission) SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); //使用者的角色集合 Set<String> list = new HashSet<>(); list.add(user.getUserType()); info.addRoles(list); //使用者的許可權集合 info.addStringPermissions(list); return info; } // 返回null的話,就會導致任何使用者訪問被攔截的請求時,都會自動跳轉到unauthorizedUrl指定的地址 return null; } }
  1. 定義ShiroConfig類,主要實現定義攔截的介面,不攔截的介面,還有沒有許可權跳轉的介面,以及密碼加密的方式等

import com.aim.chenapp.beans.ShiroRealm;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.LinkedHashMap;
import java.util.Map;

@Configuration
public class ShiroConfig {
    @Bean
    public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) {
        System.out.println("ShiroConfiguration.shirFilter()");
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        //攔截器.
        Map<String,String> filterChainDefinitionMap = new LinkedHashMap<String,String>();
        // 配置不會被攔截的連結 順序判斷
        //filterChainDefinitionMap.put("user/login", "anon");
//        filterChainDefinitionMap.put("/loginPage.html", "anon");
        //filterChainDefinitionMap.put("/power.html", "anon");
        //配置退出 過濾器,其中的具體的退出程式碼Shiro已經替我們實現了
        filterChainDefinitionMap.put("/user/login", "anon");
        filterChainDefinitionMap.put("/user/unPower", "anon");
        filterChainDefinitionMap.put("/user/doRegister", "anon");
        filterChainDefinitionMap.put("/user/register", "anon");
        filterChainDefinitionMap.put("/csyappService/selectLawyerIndex", "authc,roles[1]");
//        filterChainDefinitionMap.put("/csyappService/selectLawyerIndex", "roles[]");
//        filterChainDefinitionMap.put("/user/doLogout", "logout");
        //<!-- 過濾鏈定義,從上向下順序執行,一般將/**放在最為下邊 -->:這是一個坑呢,一不小心程式碼就不好使了;
        //<!-- authc:所有url都必須認證通過才可以訪問; anon:所有url都都可以匿名訪問-->
        filterChainDefinitionMap.put("/**", "authc");
        // 如果不設定預設會自動尋找Web工程根目錄下的"/login.jsp"頁面
        shiroFilterFactoryBean.setLoginUrl("/user/unPower");
        //未授權介面;
//        shiroFilterFactoryBean.setUnauthorizedUrl("/403");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        return shiroFilterFactoryBean;
    }

    @Bean(name = "myShiroRealm")
    public ShiroRealm myShiroRealm(HashedCredentialsMatcher matcher){
        ShiroRealm myShiroRealm = new ShiroRealm();
//        HashedCredentialsMatcher matcher = new HashedCredentialsMatcher("MD5");
//        matcher.setHashIterations(1024);
        myShiroRealm.setCredentialsMatcher(matcher);
        return myShiroRealm;
    }


    @Bean
    public SecurityManager securityManager(@Qualifier("hashedCredentialsMatcher") HashedCredentialsMatcher matcher){
        DefaultWebSecurityManager securityManager =  new DefaultWebSecurityManager();
        securityManager.setRealm(myShiroRealm(matcher));
        return securityManager;
    }

    /**
     * 密碼匹配憑證管理器
     *
     * @return
     */
    @Bean(name = "hashedCredentialsMatcher")
    public HashedCredentialsMatcher hashedCredentialsMatcher() {
        HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
          hashedCredentialsMatcher.setHashAlgorithmName("MD5");// 雜湊演算法:這裡使用MD5演算法;
        hashedCredentialsMatcher.setHashIterations(1024);// 雜湊的次數,比如雜湊兩次,相當於
        return hashedCredentialsMatcher;
    }
}

至此,shiro的配置已經完成,其他的程式碼都是非常簡單的操作,就不一一的寫了,相信大家都會。
再次提出一個小小的坑,就是用ajax傳送請求,每一次的session都 不同的解決方案,即是:在ajax上新增一個屬性

xhrFields: {
            withCredentials: true
            },

這樣每次傳送的請求session都是一個了,就不會使得驗證出現錯誤。

如有問題,敬請留言。

青春短暫,我_在路上。