{"id":37100061,"url":"https://github.com/laincloud/sso","last_synced_at":"2026-01-14T12:12:03.637Z","repository":{"id":57485163,"uuid":"57955818","full_name":"laincloud/sso","owner":"laincloud","description":"Single Sign On with OAuth2 and OpenID Connect, independent of LAIN","archived":false,"fork":false,"pushed_at":"2018-09-12T05:37:50.000Z","size":1337,"stargazers_count":23,"open_issues_count":6,"forks_count":14,"subscribers_count":7,"default_branch":"master","last_synced_at":"2024-06-19T02:59:53.248Z","etag":null,"topics":["layer2"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/laincloud.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-05-03T09:02:57.000Z","updated_at":"2024-06-19T02:59:53.249Z","dependencies_parsed_at":"2022-08-26T11:11:23.537Z","dependency_job_id":null,"html_url":"https://github.com/laincloud/sso","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/laincloud/sso","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/laincloud%2Fsso","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/laincloud%2Fsso/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/laincloud%2Fsso/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/laincloud%2Fsso/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/laincloud","download_url":"https://codeload.github.com/laincloud/sso/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/laincloud%2Fsso/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28419644,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-14T10:47:48.104Z","status":"ssl_error","status_checked_at":"2026-01-14T10:46:19.031Z","response_time":107,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["layer2"],"created_at":"2026-01-14T12:12:03.057Z","updated_at":"2026-01-14T12:12:03.629Z","avatar_url":"https://github.com/laincloud.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# SSO\n\nSSO，Single Sign On系统，是一种身份验证和授权系统，使应用程序能够获得对HTTP服务上的用户帐户的有限访问。\n\n\n##主要概念\n   - 组：组是用户的集合。组可以拥有类似组的层次结构。一个父亲组可以有一些儿子组，但是一个儿子组只能有一个父组。组之间的关系可以是管理员或普通成员。如果用户是组A中的管理员，组A是组B的管理员和父组，我们可以说用户也是组B的管理员。\n  \n   - 资源：资源可以由用户定义。资源属于一个app。对于一个应用程序，可以将资源分配给app的角色。\n  \n   - 角色：角色是一组用户，属于一个客户端。角色组中的用户可以获得角色的资源。角色可以像组一样具有层次结构。一个父亲角色可以有一些儿子角色，但一个儿子角色只能有一个父亲角色。一个app至少有一个角色，即根角色。客户端中的所有其他角色都是root角色的子角色。父角色的用户可以访问其子角色的资源。只能为资源分配leaf角色。\n  \n   - 客户端：客户端是在SSO系统中注册的一个应用程序。在SSO中注册客户端时，客户的所有者可以获得密码和app id。 Secret和app id用于用户身份验证和授权。如果您想进一步了解它，可以阅读https://oauth.net/2/\n  \n   - 申请：用户可以通过提交一个申请来申请加入群组或者角色。应用程序系统将向这些组的管理员发送电子邮件，并让他们批准或拒绝该申请。\n\n## install\n```sh\n   go get github.com/laincloud.sso\n```\n\n## usage\n ```sh\n#r/local/bin/python2\nimport time\nimport requests\nimport json\nfrom urlparse import urlparse, parse_qs\nscope = 'write:role read:role write:resource read:resource'\npayload = {'client_id':'clientId','response_type':'code','scope':scope,'redirect_uri':'redirectUri','state':'foobar'}\n#clientId is the app id, which is generated in when the app is registered\n#redirectUri is the the uri that set when the app is registered, which is used for redirect to your app from sso\nusr_msg={'login':'username','password':'password'}\n#username is your username of SSO and password is your password of SSO.\nauth_url=ssohost+'/oauth2/auth'\n#ssohost is the sso host domain\nresult=requests.post(auth_url,params=payload,data=usr_msg,allow_redirects=False)\ncode_callback_url=result.headers['location']\nauthentication=parse_qs(urlparse(code_callback_url).query)\ncode=authentication['code'][0]\nauth_msg={'client_id':'clientId','grant_type':'authorization_code','client_secret':'clientSecret','code':code,'redirect_uri':'redirectUri'}\n#clientSecret is the secret of the client, which is generated in when the app is registered.\nresult=requests.request(\"POST\", ssohost + '/oauth2/token',headers=None,params=auth_msg)\naccessinfo=result.json()\nrefresh_token=accessinfo['refresh_token']\nauth_msg={'client_id':'clientId','grant_type':'refresh_token','client_secret':'clientSecret','refresh_token':refresh_token,'redirect_uri':'redirectUri'}\nresult = requests.request(\"GET\",ssohost + '/oauth2/token',headers=None,params=auth_msg)\naccessinfo=result.json()\ntoken = 'Bearer '+accessinfo['access_token']\nheader = {'Authorization':token}\nheader2 = {'secret':'clientSecret'}\npayload = {'app_id':'clientId','type':'raw'}\n#clientId is the app id, which is generated in when the app is registered\ncreateResource = {'name':'tester','description':'testing','data':'testing'}\nupdateResource = {'name':'tester2','description':'testing2','data':'testing2'}\ncreateRole = {'app_id':clientId,'name':'test3','parent_id':roleId,'description':'testing3'}\n#roleId is the id of father role of the role you are creating\nupdateRole = {'parent_id':roleId,'name':'test4','description':'test4'}\naddMember = {'type':'normal'}\ndeleteResourceFromRole = {'action':'delete','resource_list':[id1,id2,id3]}\n#id1,id2,id3 are the ids of resource that you want to delete \naddResourceToRole = {'action':'update','resource_list':[id4,id5,id6]}\n#id4,id5,id6 are the ids of resource that you want to add\naddMembersAccumulatively = {'Action':'add','RoleId':roleId,'members':[{'user':'name1','type':'normal'},{'user':'name2','type':'normal'}]}\n#name1 and name2 are names of users that you want to add to the role\ndeleteResourceAccumulatively = [id7,id8]\n#id7, id8 are the ids of resource you want to delete\n\nprint(\"testing add members accumulatively\")\nr = requests.post(ssohost + '/api/rolemembers',data=json.dumps(addMembersAccumulatively),headers=header)\n\nprint(\"testing create resource\")\nr = requests.post(ssohost + '/api/resources',params=payload,data=json.dumps(createResource),headers=header)\n\nprint(\"testing update resource\")\nr = requests.post(ssohost + '/api/resources/id9',params=payload,data=json.dumps(updateResource),headers=header)\n#id9 is the id of resource that you want to update\n\nprint(\"testing delete resource accumulatively\")\nr = requests.post(ssohost + '/api/resourcesdelete',params=payload,headers=header,data=json.dumps(deleteResourceAccumulatively))\n\nprint(\"testing delete resource\")\nr = requests.delete(ssohost + '/api/resources/id10',params=payload,headers=header)\n#id10 is the id of resource that you want to delete\n\nprint(\"testing get rosources of app\")\nr = requests.get(ssohost + '/api/resources',params=payload,headers=header)\n\nprint(\"testing create role\")\nr = requests.post(ssohost + '/api/roles',params=payload,data=json.dumps(createRole),headers=header)\n\nprint(\"testing update role\")\nr = requests.post('https://sso-ldapyifan.yxapp.xyz/api/roles/roleId',params=payload,headers=header,data=json.dumps(updateRole))\n#roleId is the id of role you are updating\n\nprint(\"testing get role\")\nr = requests.get(ssohost + '/api/roles/roleId',params=payload,headers=header)\n#roleId is the id of the role you want to get\n\nprint(\"testing get roles\")\nr = requests.get(ssohost + '/api/roles',params=payload,headers=header)\n\nprint(\"testing delete role\")\nr = requests.delete(ssohost + '/api/roles/roleId',params=payload,headers=header)\n#roleId is the id of the role you want to delete\n\nprint(\"testing add member\")\nr = requests.put(ssohost + '/api/roles/roleId/members/name',params=payload,headers=header,data=json.dumps(addMember))\n#roleId is the id of the role you want to add member\n#name is the username of the user who you want to add\n\nprint(\"testing delete member\")\nr = requests.delete(ssohost + '/api/roles/roleId/members/name',params=payload,headers=header)\n#roleId is the id of the role you want to delete member\n#name is the username of the user who you want to delete\n\nprint(\"testing add resource to role\")\nr = requests.post(ssohost + '/api/roles/roleId/resources',params=payload,headers=header,data=json.dumps(addResourceToRole))\n#roleId is the id of the role you want to add resouce\n#note: resource can only be added to the leaf role\n\nprint(\"testing delete resource from role\")\nr = requests.post(ssohost + '/api/roles/roleId/resources',params=payload,headers=header,data=json.dumps(deleteResourceFromRole))\n#roleId is the id of the role you want to delete resouce\n```\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flaincloud%2Fsso","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flaincloud%2Fsso","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flaincloud%2Fsso/lists"}