天天看點

權限驗證原理篇

2015-08-20學到的權限驗證

“權限管理”是“權限驗證”的基礎

1)權限管理

登入時算出使用者的所有權限:

①通過使用者的角色找出相應權限

使用者–>角色–>權限

由使用者名得到userId,從user_role關聯表中獲得roleId,再從role_auth關聯表中獲得authId,由authId獲得AuthorityInfo,然後獲得AuthName,List<AuthorityInfo> authsByRole = getAuthByRole(currentId);
(這裡隻是參考,有待優化)
           

②通過直接賦予該user權限

List authsByUser = getAuthByUser(currentId);

将上面的結果都放到AuthorityInfo中

③把該使用者的權限資訊整合放到緩存Buffer中

2 )權限驗證

在登入時,使用者要同時擷取使用者權限,以下以LoginAction為例子

①找出使用者有哪些權限 acl.authorized(auth.getAuthCode())

@SuppressWarnings("serial")
public class LoginAction extends BaseLoginAction {
    private static final Logger logger = LoggerFactory.getLogger(LoginAction.class);
    private static final String prefix = "open";

    @Override
    protected Boolean hasAnyAuthority(ACL acl) {
        Boolean result = false;
        Map<String,Object> queryMap = new HashMap<String,Object>();
        queryMap.put("authCode", prefix);

        **List<AuthorityInfo> openAUthorityInfoList = authorityInfoManager.getAuthorityInfoList(queryMap);**
    //找到open下的所有權限  
        for(AuthorityInfo auth:openAUthorityInfoList) {
            if(**acl.authorized(auth.getAuthCode())**) {
            //判斷該使用者有哪些權限
                result = true;
                break;
            }
        }

        return result;
    }

getAuthorityInfoList(queryMap)的相應myBatis語句
<select id="getAuthorityInfoList" parameterType="java.util.Map" resultMap="BaseResultMap">
        select
            <include refid="Base_Column_List" />
        from
            t_dsp_auth_authority_info
        <where> 
            <if test="uthCode != null">
                and auth_code like '%${authCode}%'
            </if>
                and auth_level != 
        </where>
    </select>
    找出了所有以open開頭的authCode
           

②确認使用者在某個權限上的力度,比如商品資訊管理的增删改查

acl.check(auth.getAuthCode(),auth.getAuthStr());

//第一個參數是權限Code,第二個參數是該權限下的所有權限力度

将所有權限力度與相應使用者權限(ACLNode資料結構)的 authValue(比如1001,表示有增和查的操作力度,沒有删和改的力度)進行驗證,即确定要驗證的權限是否在目前使用者的權限集合中

ACL.java寫出了驗證方法(authorized(String authCode)和check(String authCode, String[] idxes),分别驗證使用者是否有某權限以及某權限操作力度)

public class ACL extends com.cmcc.cxb.common.Constants {
    //nodes的key是authCode,代表某個權限
        private Map<String, ACLNode> nodes;//使用者在該權限下的權限資訊Map,最主要展現在authValue,表示該使用者對應該權限的權限力度
        private Integer userType;

        public ACL(Map<String, ACLNode> nodes, Integer userType) {
            super();
            this.userType = userType;
            this.nodes = nodes;
        }

        public boolean authorized(String authCode) {
            return authorized(authCode,true);
        }

        public boolean authorized(String authCode, boolean checkType) {
            return ( checkType && AUTH_USER_TYPE_SUPER.equals(userType) ) || nodes.get(authCode) != null;
        }

        public boolean check(String authCode, String[] idxes) {

            if(AUTH_USER_TYPE_SUPER.equals(userType))
                return true;

            boolean ret = false;
            if (idxes != null)
                for (int ii = ; ii < idxes.length; ii++) {
                    ret = ret || check(authCode, idxes[ii]);   //如果idxes數組中有任何一個權限檢查通過,那麼傳回true
                }
            else
                ret = authorized(authCode);
            return ret;
        }

        //權限檢查!!!!!!!!!
        public boolean check(String authCode ,String auth){
            return check(authCode, auth, true);
        }

        //authCode:代表一個權限
        //auth:某個權限的額最細粒度的操作,例如删除delete
        public boolean check(String authCode ,String auth, boolean checkType){

            if(checkType && AUTH_USER_TYPE_SUPER.equals(userType))
                return true;

            //ACLNode的  AuthValue是什麼??
            ACLNode node = nodes.get(authCode);     //根據authCode擷取權限節點
            if (node == null)
                return false;

            String[] authes = node.getAuthes();
            String authValue = node.getAuthValue();

            try {
                int index = ArrayUtils.indexOf(authes, auth);   //确定要驗證的權限是否在目前使用者的權限集合中
                int te = ArrayUtils.indexOf(authes, "test");
                if(index == -)
                    return false;
                return check(authValue,index);
            } catch (Exception e) {
                return false;
            }
        }

        public static boolean check(String authValue,int idx) {
            if (authValue != null && authValue.length() > idx)
                return (authValue.charAt(idx) == '1');
            else if(authValue!=null)
                return false;
            return true;
        }

        public Map<String, ACLNode> getNodes() {
            return nodes;
        }

        public void setNodes(Map<String, ACLNode> nodes) {
            this.nodes = nodes;
        }

        public Integer getUserType() {
            return userType;
        }

        public void setUserType(Integer userType) {
            this.userType = userType;
        }

}
           

ACLNode.java是使用者在該權限下的權限資訊結構體

public class ACLNode {
    private Integer authId;
    private String[] authes;   //某個葉子權限的最小粒度操作,例如增加、删除、修改、排序等具體操作。
    private String authValue;   //使用者在該權限下的權限力度
    private Integer authOption;

    public Integer getAuthId() {
        return authId;
    }

    public String[] getAuthes() {
        return authes;
    }

    public String getAuthValue() {
        return authValue;
    }

    public Integer getAuthOption() {
        return authOption;
    }

    public ACLNode(Integer authId, String[] authes, String authValue,
            Integer authOption) {
        super();
        this.authId = authId;
        this.authes = authes;
        this.authValue = authValue;
        this.authOption = authOption;
    }
    /**
     * 将兩個節點合并成一個
     * @param anotherNode
     */
    public void merge(ACLNode anotherNode){
        //為空直接傳回
        if(anotherNode==null)
            return;
        //authes 相同的才允許合并
        if(!ArrayUtils.isEquals(authes, anotherNode.getAuthes()))
            return;

//      authOption = Math.max(authOption, anotherNode.getAuthOption());
        if(authValue==null)
            authValue = anotherNode.getAuthValue();
        else{
            String tmp = "";
            for(int i=;i<authes.length;i++){
                if( ACL.check(authValue,i) || ACL.check(anotherNode.getAuthValue(),i))
                    tmp += "1";
                else
                    tmp += "0";
            }
            authValue = tmp;
        }
    }

}
           

注:比如authorized()用于點選資訊管理後顯示的使用者的權限,确認有這些權限後,點選某個權限(比如商品資訊管理)再去調用check()确認該使用者對這個權限的權限力度

3)存于緩存Buffer

便于驗證,将每次使用者的權限驗證結果存于緩存,每次驗證先到緩存中查詢,再到資料庫查詢