基于Sonarqube Api---集成开发管理平台

上文//www.greatytc.com/p/a0d77b0b4809我们通过调用Sonar的API接口实现了对扫描结果获取,并通过一个计算模型完成对整个发布流的质量控制
但我们实际用的过程发现如下问题:
1.上文中接口调用没有传递任何口令但也能成功调用,原因是我们Sonar建的项目是公开的。
2.用户创建及项目创建工作繁琐,没有与内部的项目管理软件打通。
本文我们通过对Api的进一步验证解决这些问题。

1.Sonar Api说明

Sonar的Api一些主要问题,提前列出,避免入坑
1.Sonar的Api各版本差异较大,向下兼容性差
2.Sonar的Api不是很人性化,其Post的接口,参数不是写body中,而是写URL中。
3.当接口返回400/404时通常是你接口参数错了,并不能简单理解为接口地址不存在,而是应该先检查参数值,对api讲大概率是数据不存在。
4.文档是描述接口参数有时候有多个(如projectId/projectKey),很多是二选一的,全部提供了反而报错。

2.Sonar的Api安全

sonar的api调用是可以添加token的,接口是否需要token是根据要操作的接口的权限决定,有些接口强制需要token,具体可参考其api页面介绍。
Token模式
sonar的token是使用Basic Authorization认证,调用接口时在http header中添加如下信息:
header.Add("Authorization", "Basic " + basicToken);
其中值的格式是 Basic空格+token
token的格式是将 登录帐户:密码 进行Base64加密(UTF-8格式)
示例代码.netCore版本

      public Dictionary<string, string> GetAuthHeader()
        {
            Dictionary<string, string> header = new Dictionary<string, string>();
            string basicToken = EncodeBase64("admin:123456");    //帐户:密码
            header.Add("Authorization", "Basic " + basicToken);
            return header;
        }
      public static string EncodeBase64(string code, string code_type = "UTF-8")
        {
            string encode = "";
            byte[] bytes = Encoding.GetEncoding(code_type).GetBytes(code);
            try
            {
                encode = Convert.ToBase64String(bytes);
            }
            catch
            {
                encode = code;
            }
            return encode;
        }

示例代码Java版本

   String encodedText = encoder.encodeToString("admin:adssmin".getBytes("UTF-8"));       
   HttpHeaders requestHeaders = new HttpHeaders();
   requestHeaders.add("Authorization", "Basic " + encodedText);

3.Sonar的常用Api扩展封装参考

创建项目

       public string CreateProject(string name, string project)
        {
         //默认写死了private
            string postData = string.Format("name={0}&project={1}&visibility=private", name, project);
            string url = sonarRootUrl + "/api/projects/create?" + postData;
            Dictionary<string, string> header = GetAuthHeader();
            string result = HttpHelper.HttpPost(url, "", "application/json", header);
            return result;
        }

删除项目

      public string DeleteProject(string project)
        {
            string postData = string.Format("project={0}", project);
            string url = sonarRootUrl + "/api/projects/delete?" + postData;
            Dictionary<string, string> header = GetAuthHeader();
            string result = HttpHelper.HttpPost(url, "", "application/json", header);
            return result;
        }

为用户授权指定项目特定权限

         /// <summary>
        /// 为用户授权指定项目权限
        /// </summary>
        /// <param name="userId">用户帐户</param>
        /// <param name="project">project Key</param>
        /// <param name="permision">权限:admin, codeviewer, issueadmin, securityhotspotadmin, scan, user</param>
        /// <returns></returns>
        public string AddUserToProject(string userId, string permision, string projectKey)
        {
            //参数projectId与projectKey二选一,不要全部写上,建议用key,projectId需要库中找
            //权限等级admin, codeviewer, issueadmin, securityhotspotadmin, scan, user (对应界面浏览)
            //不能批量授予多个权限,如果要授权codeviewer和scan两个权限,则需要分多次调用该接口。
            string postData = string.Format("login={0}&permission={1}&projectKey={2}", userId, permision, projectKey);
            string url = sonarRootUrl + "/api/permissions/add_user?" + postData;
            Dictionary<string, string> header = GetAuthHeader();
            string result = HttpHelper.HttpPost(url, "", "application/json", header);
            return result;
        }

移除用户在指定项目中权限

   public string RemoveUserToProject(string userId, string permision, string projectKey)
        {
            string postData = string.Format("login={0}&permission={1}&projectKey={2}", userId, permision, projectKey);
            string url = sonarRootUrl + "/api/permissions/remove_user?" + postData;
            Dictionary<string, string> header = GetAuthHeader();
            string result = HttpHelper.HttpPost(url, "", "application/json", header);
            return result;
        }

创建用户并生成Token

  public string CreateUserWithToken(string userId, string mail, string userName)
        {
            string output = "";
            string postData = string.Format("mail={0}&local=false&login={1}&name={2}", mail, userId, userName);
            string url = sonarRootUrl + "/api/users/create?" + postData;
            Dictionary<string, string> header = GetAuthHeader();
            string result = HttpHelper.HttpPost(url, "", "application/json", header);
            LogHelper.Debug("CreateUserResult:" + result);
            output += result;

            postData = string.Format("login={0}&name=myToken", userId);
            url = sonarRootUrl + "/api/user_tokens/generate?" + postData;
            result = HttpHelper.HttpPost(url, postData, "application/json", header);
            LogHelper.Debug("CreateUserTokenResult:" + result);
            output += result;

            result = AddUserToGroup(userId);
            output += result;
          //这里偷了个懒没有对结果处理,你可以将数据提取整理成对接方真正需要的数据结构。
            return output; 
        }

添加用户到群组

         /// <summary>
        /// 添加用户到默认组中
        /// </summary>
        /// <param name="userId"></param>
        /// <returns></returns>
        public string AddUserToGroup(string userId, string groupName = "")
        {
            if (string.IsNullOrEmpty(groupName)) groupName = "defaultGroup";
            //如果用id需要去数据库group表看。URL中id与name二选1即可,建议用name。id=3&login={0}    name=myDefaultGroup
            string postData = string.Format("name={0}&login={1}", groupName, userId);
            string url = sonarRootUrl + "/api/user_groups/add_user?" + postData;
            Dictionary<string, string> header = GetAuthHeader();
            string result = HttpHelper.HttpPost(url, postData, "application/json", header);
            LogHelper.Debug("AddGroupResult:" + result);
            return result;
        }

移除用户从指定群组

        /// <summary>
        /// 将用户从组中移除
        /// </summary>
        /// <param name="userId"></param>
        /// <param name="groupName"></param>
        /// <returns></returns>
        public string RemoveToGroup(string userId, string groupName = "")
        {
            if (string.IsNullOrEmpty(groupName)) groupName = "defaultGroup";

            string postData = string.Format("name={0}&login={1}", groupName, userId);
            string url = sonarRootUrl + "/api/user_groups/remove_user?" + postData;
            Dictionary<string, string> header = GetAuthHeader();
            string result = HttpHelper.HttpPost(url, postData, "application/json", header);
            return result;
        }
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,372评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,368评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,415评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,157评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,171评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,125评论 1 297
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,028评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,887评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,310评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,533评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,690评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,411评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,004评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,659评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,812评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,693评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,577评论 2 353