cas_cassandra - CSDN
cas 订阅
中国科学院(英文名称:Chinese Academy of Sciences,简称中科院)成立于1949年11月,为中国自然科学最高学术机构、科学技术最高咨询机构、自然科学与高技术综合研究发展中心。中国科学院提出了建设国家创新体系的构想,先后实施知识创新工程、“创新2020”、《“率先行动”计划暨全面深化改革纲要》,提出了《迎接知识经济时代,建设国家创新体系》、《创新促进发展,科技引领未来》、《创新2050:科学技术与中国的未来》、《科技发展新态势与面向2020年的战略选择》等战略研究报告。据2018年11月中国科学院官网显示,全院共拥有12个分院、100多家科研院所、3所大学(中国科学院大学、中国科学技术大学,与上海市共建上海科技大学)、130多个国家级重点实验室和工程中心、210多个野外观测台站,承担20余项国家重大科技基础设施的建设与运行,正式职工7.1万余人,在学研究生6.4万余人;建成了完整的自然科学学科体系,物理、化学、材料科学、数学、环境与生态学、地球科学等学科整体水平已进入世界先进行列,一些领域方向也具备了进入世界第一方阵的良好态势。在解决关系国家全局和长远发展的重大问题上,已成为不可替代的国家战略科技力量。一批科学家在国家重大科技任务中发挥了关键和中坚作用,并作为我国科技界的代表活跃在国际科技前沿。 [1]  2019年9月,经党中央批准,十九届中央第四轮巡视将对中国科学院党组织开展常规巡视。 [2] 展开全文
中国科学院(英文名称:Chinese Academy of Sciences,简称中科院)成立于1949年11月,为中国自然科学最高学术机构、科学技术最高咨询机构、自然科学与高技术综合研究发展中心。中国科学院提出了建设国家创新体系的构想,先后实施知识创新工程、“创新2020”、《“率先行动”计划暨全面深化改革纲要》,提出了《迎接知识经济时代,建设国家创新体系》、《创新促进发展,科技引领未来》、《创新2050:科学技术与中国的未来》、《科技发展新态势与面向2020年的战略选择》等战略研究报告。据2018年11月中国科学院官网显示,全院共拥有12个分院、100多家科研院所、3所大学(中国科学院大学、中国科学技术大学,与上海市共建上海科技大学)、130多个国家级重点实验室和工程中心、210多个野外观测台站,承担20余项国家重大科技基础设施的建设与运行,正式职工7.1万余人,在学研究生6.4万余人;建成了完整的自然科学学科体系,物理、化学、材料科学、数学、环境与生态学、地球科学等学科整体水平已进入世界先进行列,一些领域方向也具备了进入世界第一方阵的良好态势。在解决关系国家全局和长远发展的重大问题上,已成为不可替代的国家战略科技力量。一批科学家在国家重大科技任务中发挥了关键和中坚作用,并作为我国科技界的代表活跃在国际科技前沿。 [1]  2019年9月,经党中央批准,十九届中央第四轮巡视将对中国科学院党组织开展常规巡视。 [2]
信息
主管部门
中华人民共和国国务院
拉丁文名
Academia Sinica
下辖分院
12个 [1]
现任院长
白春礼
机构简称
中科院·CAS
中文名
中国科学院
性    质
国务院直属事业单位
成立时间
1949年11月
机构地址
北京市三里河路52号
外文名
Chinese Academy of Sciences
中国科学院中科院史
1949年3月下旬,中共中央进驻北平,开始酝酿中国科学院,由郭沫若负责。1949年6月,中共中央决定由陆定一负责筹备建立科学院,恽子强和丁瓒协助,钱三强和黄宗甄参与。1949年9月,钱三强和丁瓒共同起草《建立人民科学院草案》,确定中科院基本框架。1949年9月27日,中国科学院成立,为政务院下设单位,行使管理全国科学研究事业的政府行政职能。1949年10月19日,中央人民政府委员会命郭沫若为第一任中科院院长,陈伯达、李四光、陶孟和、竺可桢为第一任中科院副院长。1949年11月1日,中科院在北京开始办公,并将11月1日定为中国科学院成立日。1949年11月5日,中科院接收国立北平研究院总办事处及所属的原子学、物理学、化学、植物学、动物学和史学6个研究,以及原中央研究院历史语言研究所在北京的图书史料整理处所。 [3]  1949年11月23日,中科院院址迁入北京王府大街9号;1950年6月23日,中科院院址迁至北京文津街3号静生生物调查所原址;1966年,中科院院址迁往北京西郊友谊宾馆北馆;1970年7月,中科院院址迁往北京三里河路52号原国家科委旧址。1949年12月16日,中科院接收静生生物调查所,成立静生生物调查所整理委员会。1949年12月21日,中科院接收西北科学考察团。1950年3月,经政务院批准,中国科学院华东办事处在上海成立;1955年2月更名为中国科学院上海办事处;1958年11月,正式成立中国科学院上海分院。1950年3月21日,中科院接收中央研究院在上海的化学、植物、动物和工学四个研究所,医学和药学两个研究所筹备处,接收北平研究院在上海的生理学、药物两个研究所和物理学研究所的结晶学研究室。 1950年4月6日,在中科院接收中央研究院办事处和社会、物理、气象、天文、地质5个研究所以及中国地理研究所。至此,中科院对原中研和北研的直属研究所接收完毕。1950年5月,首批15个研究机构及3个研究机构筹备处成立。中科院接收华北大学研究部历史研究室。1950年11月,中科院地质研究所和古生物研究所被中国地质工作计划指导委员会接收;1955年1月,中科院将此两研究所收回。1950年9月-1951年2月,中科院先后接收云南农林植物调查所、北研植物学所云南工作站、庐山森林植物园、中国西北植物调查所、国民党政府国史馆、中国海洋研究所。与中央军委气象局共同接收徐家汇观象台、佘山观象台。1950年,研究机构改组,把原有研究机构,合并改组为17个研究所、台、馆,1个委员会,另设3个研究所筹备处。1950年,中科院开始统一与审订自然科学名词;1955年11月15日,学术名词统一工作委员会划归中科院领导。1951年2月3日,中国科学院图书馆成立。1951年6月,中国科学院与教育部联合发布《1951年暑期招收研究实习员、研究生办法》,成为新中国开始研究生培养的标志。 [4]  1952年8月28日,中国科学院东北分院(现中国科学院沈阳分院、长春分院)成立。 [5]  1954年3月,中央确立建设以中国科学院为中心的国家科技体系。1954年9月21日,全国人大第一次会议通过《中华人民共和国国务院组织法》,不再把科学院列为政府部门。1954年11月10日,国务院发出《关于设立、调整中央和地方国家行政机关及其有关事项的通知》,宣布中科院不再作为国务院的组成部分,但工作仍受国务院指导。1955年5月12日,中国科学院研究生招生委员会成立。1955年6月,中国科学院学部成立。首批选聘233位学部委员。1955年8月,周恩来签发颁布《中国科学院研究生暂行条例》。1955年9月26日,中科院石油研究所学术委员会成立,各中科院下属研究所开始建立各自的学术委员会。 [6]  1956年1月1日中科院院部机构调整:(1)原“办公厅学术行政工作”与原秘书处合并成学术秘书处,原办公厅撤销。(2)成立管理局。(3)成立联络局。(4)成立科学干部培养部。(5)原人事局改称干部局。(6)撤销原编译局,将其部分工作并入科学出版社。(7)成立综合考察委员会。(8)原四个学部名称及职责均不变。1956年7月,成立计算技术所等三个研究所筹委会,并建立半导体物理研究小组。 1957年1月1日,中科院机关调整:(1)撤消学术秘书处。(2)恢复办公厅、计划局,设立宣传局和器材局。(3)干部培养部改为干部培养局。1957年,中科院党组成立“哲学社会科学部分党组”。1958年,中国科学院创办长春光学精密机械学院(现长春理工大学),1971年该校划归第五机械工业部领导。 [7-8]  1958年7月,中国科学院原子核科学委员会成立。1958年9月20日,中国科学院所属的中国科学技术大学在北京成立,中科院对中国科大实施“全院办校,所系结合”的办学方针。 [9]  1958年9月13日,中科院党组成立中国科学院党组新技术办公室。1960年1月,中科院获准建设四个配备全套设备的工厂。1960年7月2日,中国科学院新技术局成立。1960年9月,由中国科学院兰州分院开办的甘肃科学技术大学正式开学,1961年8月合并到兰州大学。 [10]  1961年6月至1962年底,进行大规模精简,撤销除新疆分院外的各省级分院和大批研究所,成立5个大区分院和华北办事处。1961年7月,“科学十四条”经中央批准正式以中央文件下发执行。1964年9月,中国科学院在北京中关村试办“中国科学院研究生院”;1966年“文革”开始后,研究生院停办。1964年10月16日,中国自行研制的第一颗原子弹爆炸成功,中国科学院为此做了大量关键性的工作。1964年12月,赵九章致函周恩来。不久,人造卫星研制工作重新上马。1965年9月,上海生物化学所、上海有机化学所与北京大学化学系合作,在世界上第一次用人工方法合成了具有较高生物活性的牛胰岛素结晶。 1967年6月,中国成功爆炸第一颗氢弹,中国科学院对此做出了重大贡献。1967年7月30日,中国科学院革命委员会成立。1967年11月28日,中国科学院地震办公室成立。1968年至1972年,中科院大批院属机构被划归国防部门,或下放地方,或撤销。1970年4月,以中科院为主研制的中国第一颗人造地球卫星成功发射。1970年7月1日,国家科委与中科院合并,成立新的中国科学院革命委员会。 1973年,国务院科教组的科技组并入中国科学院。1975年6月20日,中科院将1968年交给国防部门三十个科研事业单位中的六个从国防部门划回。1975年7月-11月,胡耀邦等整顿中科院。1977年5月,哲学社会科学部改称中国社会科学院。1977年8月,中国科学院和教育部受邓小平委托召开科教工作座谈会。1977年9月18日起,中科院不再承担原国家科委的职能。1978年3月,全国科学大会在北京召开,中国科学院承担了大会筹备的大量工作。1978年3月1日,经党中央国务院批准创办的新中国第一个研究生院——中国科学技术大学研究生院在北京成立;1982年5月,中科院党组批准同时使用校名中国科学院研究生院、中国科学技术大学研究生院(北京);2000年12月正式更名为中国科学院研究生院;2012年6月27日更名为中国科学院大学。 [11]  1978年4月,开始大规模收回和新建研究所,重建分院。同年,中国科学院在原有1所中国科技大学基础上,接收黑龙江工学院(更名为哈尔滨科学技术大学)、浙江大学、成都工学院(更名为成都科学技术大学)3所大学。从1981年起,浙江大学、成都科技大学、哈尔滨科技大学不再属科学院领导。 [12-13]  1979年1月,中国科学院学部恢复活动。次年10月,增补283位学部委员。 1981年3月6日,中央首次明确中科院办院方针。1981年5月11-20日,第四次学部委员大会召开,推选卢嘉锡任院长。1982年3月,设立面向全国的中国科学院科学基金。1984年1月,中央宣布中国科学院实行院长负责制。中科院试行博士后制度。8月8日,建立研究所开放日制度,每年在建院周年日(11月1日)前后开放一次,每次开放3天左右。1985年4月1日,全面实行所长负责制。1985年7月1日,中国科学院在全国率先建立了开放实验室,首批开放2个研究所和17个实验室。 [14]  1986年3月3日,王大珩等4位学部委员提出“关于跟踪研究外国战略高技术的建议”。“863计划“随即启动。 1987年2月,周光召院长提出新的办院方针,其后又提出实行“一院两种运行机制”。1991年,中国科学院增选210名学部委员,确定了规范化的增选制度。1993年10月,国务院批准“中国科学院学部委员”改称“中国科学院院士”。1994年1月22日,推出吸引优秀中青年科技人才的“百人计划”。1995年8月30日,中国科学院与上海市人民政府签定全面科技合作协议。在此前后,科学院在本年内还与新疆维吾尔自治区、浙江省、云南省签订了科技合作协议书。 [15-16]  1996年6月,中国科学院国家基因研究中心于在世界上首次成功构建了高分辨率的水稻基因组物理图。8月,由近代物理所和高能所合作,在世界上首次合成并鉴别出新核素镅-235。 [17]  1998年2月4日,江泽民总书记批示支持中国科学院先行进行国家创新体系试点。7月9日,知识创新工程正式启动。1999年,联合有关部门启动建设中国高速互联网络示范工程(CNCnet)骨干网。1999年,中国科学院决定在全国20所高校设立"中国科学院奖学金"。 [18]  1999年,中科院与甘肃省签订战略合作协议。 [19]  2001年,自1992年起,空间科学与应用研究中心等35个单位参与了“神舟”飞船应用系统的研究工作。 2002年1月,路甬祥院长提出新时期办院方针。2004年3月12日,中科院与黑龙江省签署全面科技合作协议。 [20]  2004年4月14日,中科院与云南省签署全面科技合作协议。 [21]  2005年3月1日,中国科学院北京分院成立。 [22]  2005年7月6日,中科院和天津市签署全面科技合作协议。 [23]  2006年3月,颁布《中国科学院章程》。2007年3月16日,中科院与新疆签署科技合作协议书。 [24]  2000年7月,中科院与山西省签订长期合作协议。 [25]  2008年9月26日,中国科学院与上海市人民政府签订《进一步深化院市合作协议书》,中国科学院上海浦东科技园同时揭牌。 [26]  2009年1月21日,中国科学院知识产权网建成开通。 [27]  2009年1月22日,中科院与广东省签署全面战略合作协议。 [28]  2009年3月3日,中科院与青岛市签署全面战略合作协议。 [29]  2009年3月6日,中国科学院与山东省人民政府在北京签署全面战略合作协议。 [30]  2009年3月10日,中科院与甘肃省在京签署《全面战略科技合作协议》。 [31]  2009年3月13日,中科院与西藏自治区、浙江省在京分别签署《科技合作协议书》、《院市全面科技合作协议》。 [32]  2009年6月10日,《创新2050:科学技术与中国的未来》系列研究报告发布。2010年3月12日,中科院与贵州省签署全面战略合作协议。 [33]  2010年3月31日,国务院决定中国科学院实施“创新2020”,创新2020随即启动。2011年3月,白春礼院长提出“民主办院、开放兴院、人才强院”发展战略。2011年3月10日,中科院与辽宁省签署全面科技合作协议。 [34]  2011年10月31日,中科院与河北省签署全面战略科技合作协议。 [35]  2012年3月,中科院分别与江西省、甘肃省在北京签署《江西省人民政府与中国科学院共建江西省科学院协议》、《共同支持甘肃省科学院发展协议》。 [36-37]  2012年11月25日,中国科学院与广西壮族自治区人民政府签署科技合作协议和共同支持广西科学院建设和发展协议。 [38]  2013年1月28日,中国科学院与中国工程物理研究院签署战略合作框架协议。 [39]  2013年7月17日,习近平总书记考察中科院,提出“四个率先”。 [6]  2013年9月30日,中国科学院与上海市共建的上海科技大学正式建立。 [40]  2015年7月28日,中科院与上海市签署全面深化合作协议。 [41]  2016年8月16日,中国科学院与河南省人民政府在京签署科技合作协议。 [42]  2016年9月21日,中科院与四川省签署第四轮全面科技合作协议。 [43]  2016年11月19日,中国科学院与深圳市人民政府签署在深合作办学备忘录,双方将依托中国科学院深圳先进技术研究院合作建设中国科学院大学深圳校区。 [44]  2016年12月8日,中国科学院与广东省人民政府签署“十三五”全面战略合作协议。 [45]  2017年1月,中国科学院与江西省人民政府签署全面战略合作协议。 [46]  2017年11月10日,中科院与国家海洋局签署战略合作框架协议。 [47]  2017年11月22日,中科院与吉林省签署科技创新合作协议。 [48]  2017年12月3日,中科院与深圳市签署合作协议,共建深圳国际科技产业创新中心。 [49]  2017年12月20日,中科院与福建省政府、福州市政府在福州签署共建中国科学院大学福建学院协议。 [50]  2018年2月6日,中科院与陕西省签署共建西安科学园协议。 [51]  2018年3月22日,中科院与军事科学院签署战略合作框架协议。 [52]  2018年4月4日,中国科学院与重庆市人民政府在重庆签署共建新型科教创产融合发展联合体战略合作协议,双方携手共建中国科学院大学重庆学院。 [53]  2018年11月4日,中科院倡议并联合40多个国家、地区的科教机构和相关国际组织发起成立了“一带一路”国际科学组织联盟(ANSO)。 [54]  2018年11月8日,中国科学院与香港特区政府在港签署《关于中国科学院在香港设立院属机构的备忘录》,推动中科院在港的研发工作。 [55]  2018年11月16日,中国科学院与深圳市人民政府签署协议书,合作共建中国科学院深圳理工大学。 [56]  2018年11月18日,中科院与广东省签署共同推进粤港澳大湾区国际科技创新中心建设合作协议。 [57]  2018年11月21日,中国科学院分别与内蒙古自治区、中国铁路总公司签署全面科技合作协议、战略合作协议。 [58-59]  2019年1月31日,中国科学院与中国核工业集团有限公司签署全面战略合作协议。 [60]  2020年5月13日,作为第一批倡议方,与国家发展改革委等发起“数字化转型伙伴行动”倡议。 [61] 
收起全文
精华内容
参与话题
  • 我们在上一篇文章中已经介绍了cas以及它的工作流程。 单点登录(一)-----理论-----单点登录SSO的介绍和CAS+选型本章我们开始动手搭建一个完整的cas服务实现2个web之间的单点登录。简化声明我们这里为了感受完整的...



    我们在上一篇文章中已经介绍了cas以及它的工作流程。

     单点登录(一)-----理论-----单点登录SSO的介绍和CAS+选型


    本章我们开始动手搭建一个完整的cas服务实现2个web之间的单点登录。



    简化声明

    我们这里为了感受完整的简单的CAS搭建流程,这里有两个地方做了简化:

    认证方式使用的测试类型的认证方式

    我们在上一篇已经学习了CAS的认证方式支持很多种,可以是xml,可以是LADP服务,可以是数据库,我们这里因为是测试,所以先使用最简单的认证方式,也就是cas原生提供的测试用的一种方式,帐号密码是写死的。

    去除https的证书认证

    我们在看网上很多CAS搭建的教程中会看到很多都有配置导入导入证书这个步骤,很繁琐而且容易失败或者出问题。

    测试环境中自己用JDK自带的keytool工具生成证书。

    如果以后真正在产品环境中使用肯定要去证书提供商去购买,证书认证一般都是由VeriSign认证,

    中文官方网站: http://www.verisign.com/cn/。 

    也可以申请免费的StartSSL CA证书: StartSSL(公司名:StartCom)也是一家CA机构,它的根证书很久之前就被一些具有开源背景的浏览器支持(Firefox浏览器、谷歌Chrome浏览器、苹果Safari浏览器等)。 

    申请地址:http://www.startssl.com

     申请方法参考: http://www.linuxidc.com/Linux/2011-11/47478.htm 

    而且不是官方付费购买的证书权限的话,浏览器还会报证书过期等等。

    CAS默认使用的是HTTPS协议,如果对安全要求不高,可使用HTTP协议。

    所以不一定需要配置证书,我们后面会讲到启用https时证书怎么配置。

    但是这里先使用http协议,可以使我们的搭建流程更简便。






    cas server版本选择

    我们在cas的github项目中可以看到版本的发布情况,我们可以自己根据特性来选择版本。

    https://github.com/apereo/cas/releases

    点击DOCS然后查看Getting Started中的Installation Requirements可以看到需要哪些支持。

    原则上越新的稳定版本越好,但是看到5.0版本以上基本都需要jdk1.8以上的支持,而且需要gradle构建工具来进行编译,4.1.11则需要maven3.3版本进行编译。

    因为新版本的源码部署打包稍微麻烦一些,我们独立出来讲解在

    单点登录(三)-----实战-----cas server 源码下载和部署

    官网中4.0.0版本是有发布直接可用的war包版本的,我们直接使用4.0.0作为例子。

    所以我选择了 CAS v4.0.0版本。

    https://github.com/apereo/cas/releases

    在下载页面找到4.0.0后选择 release.zip下载(只有4.0.0有这个选项,其他版本都只有源码):







    cas server解压war包部署到tomcat


    war包名修改

    我们把下载好的release.zip解压出来得到cas server 4.0.0的文件夹,文件夹中有module文件夹里面有可用的war包。

    注意只有4.0.0版本的有module文件夹和可用war包,其他版本的源码zip解压出来是没有的,需要自己编译打包。





    ps:!!!!注意是cas-server-webapp-4.0.0.war包,别用错cas-management-webapp-4.0.0.war了,否则后面会出现页面重定向错误http://localhost:9000/cas/login?service=http%3A%2F%2Flocalhost%3A9000%2Fcas-management%2Fj_spring_cas_security_check。

    然后我们把war包复制到tomcat的webapp文件夹,为了方便访问,我们先把war包名称修改成cas.war。运行tomcat即可解压出cas-server项目。

    这样我们就能访问cas-server项目了。



    端口修改

    如果tomcat的端口不是用的8080的话 还需要在解压出来的cas工程中修改一下配置文件cas.properties中的server.name,如图:



    我这里把它修改成http://localhost:9000

    然后重启tomcat

    然后访问的时候就能使用

    http://localhost:9000/cas/login

    访问。

    这里的9000端口是我的tomcat设置的端口,读者自己对应自己的端口。





    然后我们尝试使用http://localhost:9000/cas/login访问。

    出现如下页面则部署成功:



    但是我们注意到这里有一句提醒:


    You are currently accessing CAS over a non-secure connection. Single Sign On WILL NOT WORK. In order to have single sign on work, you MUST log in over HTTPS.

    意思是我们不是通过https协议连接的。



    去掉https验证

    cas默认是采用https模式的,我们没有配置证书,所以要么配置证书,要么取消https的过滤,让http协议也能访问。

    我们这里取消https的配置,让http也能访问。

    需要修改三个地方的配置(针对4.0.0版本,其他版本的话第一处必改,其他的看看还有没有带有cookie的文件名)

    修改一deployerConfigContext.xml增加参数p:requireSecure="false"

    我们在tomcat的webapp中找到 cas/WEB-INF/deployerConfigContext.xml


    里面有一句

    <bean class="org.jasig.cas.authentication.handler.support.HttpBasedServiceCredentialsAuthenticationHandler"
    p:httpClient-ref="httpClient"/>

    这里需要增加参数p:requireSecure="false",requireSecure属性意思为是否需要安全验证,即HTTPS,false为不采用。修改后为:

      <bean class="org.jasig.cas.authentication.handler.support.HttpBasedServiceCredentialsAuthenticationHandler"
     p:httpClient-ref="httpClient"  p:requireSecure="false"/>




    修改二ticketGrantingTicketCookieGenerator.xml修改p:cookieSecure="false"

     我们在tomcat的webapp中找到cas/WEB-INF/spring-configuration/ticketGrantingTicketCookieGenerator.xml


    <bean id="ticketGrantingTicketCookieGenerator" class="org.jasig.cas.web.support.CookieRetrievingCookieGenerator"

          p:cookieSecure="true"

          p:cookieMaxAge="-1"

          p:cookieName="CASTGC"

          p:cookiePath="/cas" />

     参数p:cookieSecure="true",同理为HTTPS验证相关,TRUE为采用HTTPS验证,FALSE为不采用https验证。

    参数p:cookieMaxAge="-1",简单说是COOKIE的最大生命周期,-1为无生命周期,即只在当前打开的IE窗口有效,IE关闭或重新打开其它窗口,仍会要求验证。可以根据需要修改为大于0的数字,比如3600等,意思是在3600秒内,打开任意IE窗口,都不需要验证。

     这里把 cookieSecure修改为false就行了







    修改三 warnCookieGenerator.xml修改p:cookieSecure="false"


    我们在tomcat的webapp中找到cas/WEB-INF/spring-configuration/warnCookieGenerator.xml



    里面有

    <bean id="warnCookieGenerator" class="org.jasig.cas.web.support.CookieRetrievingCookieGenerator"
    p:cookieSecure="true"
    p:cookieMaxAge="-1"
    p:cookieName="CASPRIVACY"
    p:cookiePath="/cas" />

     参数p:cookieSecure="true",同理为HTTPS验证相关,TRUE为采用HTTPS验证,FALSE为不采用https验证。

     这里把 cookieSecure修改为false就行了。




    三个地方都修改好后我们就可以启动tomcat了,这时候https的方式已经取消,可以使用http的方式访问了。



    ps:我们这里还没配置cas 客户端也就是我们的web应用,但是记得把客户端filter中的http链接也修改成http即可。  

    例如:所有https://localhost:9000/cas   更改为 http://localhost:9000/cas


    PS:配置完http方式访问之后页面上的 提示还是存在的,如果我们之后会对登录界面样式完全改版,所以可以不用管它。如果还是需要把它去掉的话,cas统一认证的登陆页面位于:cas目录/WEB-INF/view/jsp/default 文件夹里,其中ui/casLoginView.jsp为登陆页面。我们找到这段代码删掉即可。

    <c:if test="${not pageContext.request.secure}">
      <div id="msg" class="errors">
        <h2>Non-secure Connection</h2>
        <p>You are currently accessing CAS over a non-secure connection.  Single Sign On WILL NOT WORK.  In order to have single sign on work, you MUST log in over HTTPS.</p>
      </div>
    </c:if>








    尝试登录


    我们之前说过cas server对用户密码的认证是支持很多种方式的,我们可以进行配置。

    4.0.0版本的cas是在deployerConfigContext.xml文件中进行配置的。我们找到这个部分。

        <!--
           | TODO: Replace this component with one suitable for your enviroment.
           |
           | This component provides authentication for the kind of credential used in your environment. In most cases
           | credential is a username/password pair that lives in a system of record like an LDAP directory.
           | The most common authentication handler beans:
           |
           | * org.jasig.cas.authentication.LdapAuthenticationHandler
           | * org.jasig.cas.adaptors.jdbc.QueryDatabaseAuthenticationHandler
           | * org.jasig.cas.adaptors.x509.authentication.handler.support.X509CredentialsAuthenticationHandler
           | * org.jasig.cas.support.spnego.authentication.handler.support.JCIFSSpnegoAuthenticationHandler
           -->
        <bean id="primaryAuthenticationHandler"
              class="org.jasig.cas.authentication.AcceptUsersAuthenticationHandler">
            <property name="users">
                <map>
                    <entry key="casuser" value="Mellon"/>
                </map>
            </property>
        </bean>



    AcceptUsersAuthenticationHandler 是普通认证类型,也就是直接对照帐号密码。

    可以看到测试版本的帐号是casuser密码是 Mellon,是写死的。我们就用这个帐号密码进行登录即可,或者修改成你喜欢的帐号密码再启动tomcat。

    登录后显示登录成功说明我们的cas server部署成功了。

    接着我们就要开始部署cas client了,也就是把我们的web项目于cas server关联起来。








    cas client的部署和设置


    我们在官网下载到的cas client项目不是web 项目的形式(不是war包),不能直接使用,它只是一个jar包,需要融合到我们的web项目,使web项目变得支持cas服务。

    CAS client是部署在应用端的,因为通常单点登陆都会涉及到对已有系统的改造。所以,client端的侵入性就变的很重要。侵入性越小,越容易部署和测试。CAS框架的优点之一就在于它的client端对应用系统的侵入性比较小。对于Java的Web项目来说,你只需要在web.xml里面添加一个filter,拷贝CAS client的jar包到应用系统,然后改造登陆认证过程即可。如果CAS server用的是Https,那就还需要将证书导入到JVM的可信证书域中,通常是($JAVA_HOME/lib/security/cacerts)。




    新建web项目

    生成环境中是把已有的web项目进行改造,我们这里为了简化,可以新建一个web项目。

    我在myeclipse中新建两个maven类型的web项目如下(分别命名为cas-client1和cas-client2):







    cas-client-core.jar包引用

    这里拷贝的cas client的jar包也就是官网提供的cas client项目。下载地址:

    https://github.com/apereo/java-cas-client

    下载到的是源代码,需要把cas-client-core打包成jar包才能使用。

    将cas-client-core-3.2.1.jar放入应用WEB-INF/lib下即可。


    如果我们的web项目是maven项目的话就方便很多,直接在pom.xml文件添加以下引用即可:

    <dependency>
        <groupId>org.jasig.cas.client</groupId>
        <artifactId>cas-client-core</artifactId>
        <version>${java.cas.client.version}</version>
    </dependency>

    ${java.cas.client.version}替换成我们使用的client发布的版本号。

    我们在tags中可以看到有哪些产品号



    所以我们这里的会使用3.4.1版本。pom.xml中添加的代码为:

    <dependency>
        <groupId>org.jasig.cas.client</groupId>
        <artifactId>cas-client-core</artifactId>
        <version>3.4.1</version>
    </dependency>
    






    域名映射

    正式生产环境中,cas client配置cas server的地址时如果是使用https验证的话不能使用ip的,只能用域名,域名需要与生成证书时填写的域名一样,如果是http模式验证的话,则cas server的地址可以使用ip

    我们这里是做测试,所以可以在cas client所在的系统上修改hosts文件做域名映射。

    否则的话会报各种错误。

    win 10的hosts文件在 C:\WINDOWS\system32\drivers\etc

    编辑新增127.0.0.1 casserver 



    保存

    如果保存不了的话是权限问题,对着hosts文件右键属性安全里去设置即可。

    验证一下  运行tomcat 我们的cas server能不能用域名访问,之前的访问地址是

    http://localhost:9000/cas/login

    现在尝试用

    http://casserver:9000/cas/login 访问。

    访问成功,域名映射就设置好了。







    web.xml配置filter

    包引入之后我们就可以使用cas的服务了,主要是要配置一下过滤器。

    cas有几个重要的filter:
    org.jasig.cas.client.authentication.AuthenticationFilter (负责客户端认证)
    org.jasig.cas.client.validation.Cas20ProxyReceivingTicketValidationFilter (按照CAS2体系结构校验Ticket)
    org.jasig.cas.client.util.HttpServletRequestWrapperFilter (包装request.getRemoteUser()数据)
    org.jasig.cas.client.util.AssertionHolder(来获取用户的登录名)


    web.xml中需要增加的代码格式为(还需要根据我们的环境进行参数调整):

    <!-- ****************** 单点登录开始 ********************-->
        <!-- 用于实现单点登出功能  可选 -->
        <listener>
            <listener-class>org.jasig.cas.client.session.SingleSignOutHttpSessionListener</listener-class>
        </listener>
    
    
    
    
    
    
    
    
        <!-- 该过滤器用于实现单点登出功能,单点退出配置,一定要放在其他filter之前 可选 -->
        <filter>
            <filter-name>CAS Single Sign Out Filter</filter-name>
            <filter-class>org.jasig.cas.client.session.SingleSignOutFilter</filter-class>
            <init-param>
                <param-name>casServerUrlPrefix</param-name>
                <param-value>http://casserver:9000/cas/</param-value>
            </init-param>
        </filter>
        <filter-mapping>
            <filter-name>CAS Single Sign Out Filter</filter-name>
            <url-pattern>/*</url-pattern>
        </filter-mapping>
    
    
    
    
    
    
    
    
        <!-- 该过滤器负责用户的认证工作,必须 -->
        <filter>
            <filter-name>CASFilter</filter-name>
            <filter-class>org.jasig.cas.client.authentication.AuthenticationFilter</filter-class>
            <init-param>
                <!--casServerLoginUrl:cas服务的登陆url -->
                <param-name>casServerLoginUrl</param-name>
                <param-value>http://casserver:9000/cas/login</param-value>
            </init-param>
            <init-param>
                <!--serverName:本项目的ip+port -->
                <param-name>serverName</param-name>
                <param-value>http://localhost:9000</param-value>
            </init-param>
            <init-param>
                <param-name>useSession</param-name>
                <param-value>true</param-value>
            </init-param>
            <init-param>
                <param-name>redirectAfterValidation</param-name>
                <param-value>true</param-value>
            </init-param>
        </filter>
        <filter-mapping>
            <filter-name>CASFilter
    </filter-name>
            <url-pattern>/*</url-pattern>
        </filter-mapping>
    
    
    
    
    
    
    
    
        <!-- 该过滤器负责对Ticket的校验工作,必须-->
        <filter>
            <filter-name>CAS Validation Filter</filter-name>
            <filter-class>
                org.jasig.cas.client.validation.Cas20ProxyReceivingTicketValidationFilter
            </filter-class>
            <init-param>
                <param-name>casServerUrlPrefix</param-name>
                <param-value>http://casserver:9000/cas/</param-value>
            </init-param>
            <init-param>
                <param-name>serverName</param-name>
                <param-value>http://localhost:9000</param-value>
            </init-param>
        </filter>
        <filter-mapping>
            <filter-name>CAS Validation Filter</filter-name>
            <!-- 对项目中的哪些路径做登录拦截-->
            <url-pattern>/*</url-pattern>
        </filter-mapping>
    
    
    
    
    
    
    
    
        <!-- 该过滤器对HttpServletRequest请求包装, 可通过HttpServletRequest的getRemoteUser()方法获得登录用户的登录名,可选 -->
    
    
    
    
    
    
    
    
        <filter>
            <filter-name>CAS HttpServletRequest Wrapper Filter</filter-name>
            <filter-class>
                org.jasig.cas.client.util.HttpServletRequestWrapperFilter
            </filter-class>
        </filter>
        <filter-mapping>
            <filter-name>CAS HttpServletRequest Wrapper Filter</filter-name>
            <url-pattern>/*</url-pattern>
        </filter-mapping>
    
    
    
    
    
    
    
    
        <!-- 该过滤器使得可以通过org.jasig.cas.client.util.AssertionHolder来获取用户的登录名。
             比如AssertionHolder.getAssertion().getPrincipal().getName()。 
             这个类把Assertion信息放在ThreadLocal变量中,这样应用程序不在web层也能够获取到当前登录信息 -->
        <filter>
            <filter-name>CAS Assertion Thread Local Filter</filter-name>
            <filter-class>org.jasig.cas.client.util.AssertionThreadLocalFilter</filter-class>
        </filter>
        <filter-mapping>
            <filter-name>CAS Assertion Thread Local Filter</filter-name>
            <url-pattern>/*</url-pattern>
        </filter-mapping>
        <!-- ****************** 单点登录结束 ********************-->
    

    对于这些参数的含义和解释可以参考官方文档也可以看我们之前的第一篇文章:

    https://github.com/apereo/java-cas-client

    http://blog.csdn.net/zzq900503/article/details/54646828


    ps:

    域名映射小节已经讲了,这里再强调一次。

    如果是没有取消https认证的话casServerLoginUrl和casServerUrlPrefix必须使用域名,且域名要和证书中的“名字与姓氏”完全相同,没有域名的可以配置本地hosts做映射 。我们这里已经去取消了https的协议,让http也能访问所以不需要与证书对应,但是也需要设置一下域名映射。


    serverName:是cas-client本项目的ip+port,我们这里cas client项目也放在tomcat 9000中,所以端口也是一样的。



    最终的web.xml为:

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app version="2.5" 
    	xmlns="http://java.sun.com/xml/ns/javaee" 
    	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
    	http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
      <display-name></display-name>	
      <welcome-file-list>
        <welcome-file>index.jsp</welcome-file>
      </welcome-file-list>
      
     <!-- ****************** 单点登录开始 ********************-->
        <!-- 用于实现单点登出功能  可选 -->
        <listener>
            <listener-class>org.jasig.cas.client.session.SingleSignOutHttpSessionListener</listener-class>
        </listener>
    
    
    
    
    
    
    
    
        <!-- 该过滤器用于实现单点登出功能,单点退出配置,一定要放在其他filter之前 可选 -->
        <filter>
            <filter-name>CAS Single Sign Out Filter</filter-name>
            <filter-class>org.jasig.cas.client.session.SingleSignOutFilter</filter-class>
            <init-param>
                <param-name>casServerUrlPrefix</param-name>
                <param-value>http://casserver:9000/cas/</param-value>
            </init-param>
        </filter>
        <filter-mapping>
            <filter-name>CAS Single Sign Out Filter</filter-name>
            <url-pattern>/*</url-pattern>
        </filter-mapping>
    
    
    
    
    
    
    
    
        <!-- 该过滤器负责用户的认证工作,必须 -->
        <filter>
            <filter-name>CASFilter</filter-name>
            <filter-class>org.jasig.cas.client.authentication.AuthenticationFilter</filter-class>
            <init-param>
                <!--casServerLoginUrl:cas服务的登陆url -->
                <param-name>casServerLoginUrl</param-name>
                <param-value>http://casserver:9000/cas/login</param-value>
            </init-param>
            <init-param>
                <!--serverName:本项目的ip+port -->
                <param-name>serverName</param-name>
                <param-value>http://localhost:9000</param-value>
            </init-param>
            <init-param>
                <param-name>useSession</param-name>
                <param-value>true</param-value>
            </init-param>
            <init-param>
                <param-name>redirectAfterValidation</param-name>
                <param-value>true</param-value>
            </init-param>
        </filter>
        <filter-mapping>
            <filter-name>CASFilter</filter-name>
            <url-pattern>/*</url-pattern>
        </filter-mapping>
    
    
    
    
    
    
    
    
        <!-- 该过滤器负责对Ticket的校验工作,必须-->
        <filter>
            <filter-name>CAS Validation Filter</filter-name>
            <filter-class>
                org.jasig.cas.client.validation.Cas20ProxyReceivingTicketValidationFilter
            </filter-class>
            <init-param>
                <param-name>casServerUrlPrefix</param-name>
                <param-value>http://casserver:9000/cas/</param-value>
            </init-param>
            <init-param>
                <param-name>serverName</param-name>
                <param-value>http://localhost:9000</param-value>
            </init-param>
        </filter>
        <filter-mapping>
            <filter-name>CAS Validation Filter</filter-name>
            <!-- 对项目中的哪些路径做登录拦截-->
            <url-pattern>/*</url-pattern>
        </filter-mapping>
    
    
    
    
    
    
    
    
        <!-- 该过滤器对HttpServletRequest请求包装, 可通过HttpServletRequest的getRemoteUser()方法获得登录用户的登录名,可选 -->
    
    
    
    
    
    
    
    
        <filter>
            <filter-name>CAS HttpServletRequest Wrapper Filter</filter-name>
            <filter-class>
                org.jasig.cas.client.util.HttpServletRequestWrapperFilter
            </filter-class>
        </filter>
        <filter-mapping>
            <filter-name>CAS HttpServletRequest Wrapper Filter</filter-name>
            <url-pattern>/*</url-pattern>
        </filter-mapping>
    
    
    
    
    
    
    
    
        <!-- 该过滤器使得可以通过org.jasig.cas.client.util.AssertionHolder来获取用户的登录名。
             比如AssertionHolder.getAssertion().getPrincipal().getName()。 
             这个类把Assertion信息放在ThreadLocal变量中,这样应用程序不在web层也能够获取到当前登录信息 -->
        <filter>
            <filter-name>CAS Assertion Thread Local Filter</filter-name>
            <filter-class>org.jasig.cas.client.util.AssertionThreadLocalFilter</filter-class>
        </filter>
        <filter-mapping>
            <filter-name>CAS Assertion Thread Local Filter</filter-name>
            <url-pattern>/*</url-pattern>
        </filter-mapping>
        <!-- ****************** 单点登录结束 ********************-->
    </web-app>
    







    测试单点登录cas服务


    到这里我们的两个client也部署好了,现在可以测试sso是否能够实现了。

    我们先分别把cas-client1的index.jsp和cas-client2的index.jsp页面修改一下,使它们能够区分出来。

    我这里改的是body的内容,分别改成cas-client1和cas-client2。



    然后把cas-client1和cas-client2两个项目都加入到tomcat 9000的webapp中 运行tomcat。




    启动tomcat确认不报错之后我们访问

    localhost:9000/cas-client2

    发现它成功被拦截了。

    跳转到了

    http://casserver:9000/cas/login?service=http%3A%2F%2Flocalhost%3A9000%2Fcas-client2%2F

    然后我们再访问

    localhost:9000/cas-client1

    则是被拦截跳转到了

    http://casserver:9000/cas/login?service=http%3A%2F%2Flocalhost%3A9000%2Fcas-client1%2F









    然后我们输入帐号密码。

    casuser和Mellon

    登录成功后调整到了cas-client1的首页


    然后我们再直接访问cas-client2的项目地址

    localhost:9000/cas-client2

    发现不需要再输入帐号密码,也可以登录了。




    到这里说明我们的SSO单点登录已经部署验证成功了。


    后续我们会进行一些优化和调优等等。






    展开全文
  • 浅谈CAS以及CAS在java中应用

    万次阅读 多人点赞 2019-01-02 21:48:20
    浅谈CAS以及CAS在java中应用 cas是什么? cas是compareandswap的简称,从字面上理解就是比较并更新,简单来说:从某一内存上取值V,和预期值A进行比较,如果内存值V和预期值A的结果相等,那么我们就把新值B更新到...

    浅谈CAS以及CAS在java中应用

    cas是什么?

    cas是compareandswap的简称,从字面上理解就是比较并更新,简单来说:从某一内存上取值V,和预期值A进行比较,如果内存值V和预期值A的结果相等,那么我们就把新值B更新到内存,如果不相等,那么就重复上述操作直到成功为止。

    cas能做什么?

    上面我们了解了cas是什么了,那么它能解决什么问题呢?它可以解决多线程并发安全的问题,以前我们对一些多线程操作的代码都是使用synchronize关键字,来保证线程安全的问题;现在我们将cas放入到多线程环境里我们看一下它是怎么解决的,我们假设有A、B两个线程同时执行一个int值value自增的代码,并且同时获取了当前的value,我们还要假设线程B比A快了那么0.00000001s,所以B先执行,线程B执行了cas操作之后,发现当前值和预期值相符,就执行了自增操作,此时这个value = value + 1;然后A开始执行,A也执行了cas操作,但是此时value的值和它当时取到的值已经不一样了,所以此次操作失败,重新取值然后比较成功,然后将value值更新,这样两个线程进入,value值自增了两次,符合我们的预期。

    cas在java中的应用

    是不是感觉cas很好用,那么在java中有对应的实现吗?有的!java从jdk1.5就将cas引入并且使用了,java中的Atomic系列就是使用cas实现的,下面我们就用AtomicInteger类看一下java是怎么实现的吧。

    进入到AtomicInteger类里边之后,我们发现它使用volatile声明了一个变量,至于volatile有什么特性,我就不详细赘述了,简单来说volatile声明这个变量是易变的,当线程拿到这个值并且更新之后还要将更新后的值同步到主内存里边,供之后的线程调用。

    好了,了解了volatile的特性之后,我们再来看一下它怎么实现自增的吧。
    在这里插入图片描述

    AtomicInteger有一个incrementAndGet的自增方法,在一个循环里,每次去获取当前的值current,然后将当前值current+1赋值给next,然后将current和next放到compareAndSet中进行比较,如果返回true那么就return next的值,如果失败,那么继续进行上述操作,是不是很眼熟这个操作,是的,你没看错,这里就是使用了cas操作,看到这里是不是感觉java很直白,哈哈。

    好的,我们再来看compareAndSet是不是如我们所想的那样使用了cas呢,我们再进入compareAndSet方法中一探究竟。

    在这里插入图片描述
    可以看到这个compareAndSet方法有两个参数,分别叫expect和update,从字面上理解就是预期的值和更新的值,OK,我们再来看里边,里边调用了一个compareAndSwapInt的方法,有四个参数分别是当前的值this、valueOffset、预期值expect、更新的值update,其中expect和update是通过参数传过来的,你们还记得这两个值分别是什么吗?不记得的童鞋们请网上翻,没错就是incrementAndGet方法中的current和next,好的,我们来梳理一下this当前值和预期值expect也就是current进行比较,如果相等,就把值更新为update也就是next,这样此次自增操作完成!至于valueOffset容我买个关子。

    CAS有没有什么不好的隐患呢?

    毫无疑问肯定有的!
    1、首先就是经典的ABA问题
    何为ABA呢?我们还是以两个线程L、N进行自增操作为例,线程L、N同时获取当前的值A,只不过此时线程N比较快,它在L操作之前,进行了两次操作,第一次将值从A 改为了B,之后又将B改为了A,那么在线程L操作的 时候发现当前的值还是A,符合预期,那么它也会更新成功,从操作上看并没有什么不对,更新成功也是对的,但是这样是有隐患的,这个网上有好多关于ABA问题隐患的解读,我觉得有一个老哥使用链表的表述最为贴切,这个是我很久之前看的,我现在也找不到这个老哥关于这个问题解读的帖子了,大家自行搜索一下吧,为了解决这个问题,java引入了版本的概念,相当于上述操作变为了A1----B2----A3,这样就非常明确了,这个版本相信大家也猜到那就是valueOffset,所以在AtomicInteger中进行cas操作时除了this、expect、update之外还有一个valueOffset的参数进行版本的区分,就是为了解决ABA问题的。

    2、长时间自旋非常消耗资源
    先说一下什么叫自旋,自旋就是cas的一个操作周期,如果一个线程特别倒霉,每次获取的值都被其他线程的修改了,那么它就会一直进行自旋比较,直到成功为止,在这个过程中cpu的开销十分的大,所以要尽量避免。

    第一次写博客,如有问题,请大家多多指正,thanks!
    联系方式:
    邮件:lnjavamail@163.com
    微信:ln_coder

    展开全文
  • 面试必问的CAS,你懂了吗?

    万次阅读 多人点赞 2020-10-19 22:51:09
    面试必问的CAS,你懂了吗?

    目录

    概述

    案例

    CAS是什么?

    源码分析

    intel手册对lock前缀的说明如下:

    CAS的缺点:

    循环时间长开销很大:

    只能保证一个变量的原子操作:

    什么是ABA问题?ABA问题怎么解决?


    概述

    CAS(Compare-and-Swap),即比较并替换,是一种实现并发算法时常用到的技术,Java并发包中的很多类都使用了CAS技术。CAS也是现在面试经常问的问题,本文将深入的介绍CAS的原理。

     

    案例

    介绍CAS之前,我们先来看一个例子。

    /**
     * @author joonwhee
     * @date 2019/7/6
     */
    public class VolatileTest {
        
        public static volatile int race = 0;
    
        private static final int THREADS_COUNT = 20;
        
        public static void increase() {
            race++;
        }
    
        public static void main(String[] args) throws InterruptedException {
            Thread[] threads = new Thread[THREADS_COUNT];
            for (int i = 0; i < THREADS_COUNT; i++) {
                threads[i] = new Thread(new Runnable() {
                    @Override
                    public void run() {
                        for (int i = 0; i < 10000; i++) {
                            increase();
                        }
                    }
                });
                threads[i].start();
            }
    
            while (Thread.activeCount() > 1) {
                Thread.yield();
            }
            System.out.println(race);
        }
    }

     

    这个例子有些网友反馈会进入死循环,我后面也发现了,在IDEA的RUN模式下确实会陷入死循环,通过 Thread.currentThread().getThreadGroup().list(); 代码可以打印出当前的线程情况如下:

    java.lang.ThreadGroup[name=main,maxpri=10]
        Thread[main,5,main]
        Thread[Monitor Ctrl-Break,5,main]

     

    可以看到,除了Main方法线程后,还有一个Monitor Ctrl-Break线程,这个线程是IDEA用来监控Ctrl-Break中断信号的线程。

    解决死循环的办法:如果是IDEA,可以使用DEBUG模式运行就可以,或者使用下面这段代码。

    import java.util.concurrent.CountDownLatch;
    
    /**
     * @author joonwhee
     * @date 2019/7/6
     */
    public class VolatileTest {
        
        public static volatile int race = 0;
    
        private static final int THREADS_COUNT = 20;
    
        private static CountDownLatch countDownLatch = new CountDownLatch(THREADS_COUNT);
    
        public static void increase() {
            race++;
        }
    
        public static void main(String[] args) throws InterruptedException {
            Thread[] threads = new Thread[THREADS_COUNT];
            for (int i = 0; i < THREADS_COUNT; i++) {
                threads[i] = new Thread(new Runnable() {
                    @Override
                    public void run() {
                        for (int i = 0; i < 10000; i++) {
                            increase();
                        }
                        countDownLatch.countDown();
                    }
                });
                threads[i].start();
            }
            countDownLatch.await();
            System.out.println(race);
        }
    }

     

    上面这个例子在volatile关键字详解文中用过,我们知道,运行完这段代码之后,并不会获得期望的结果,而且会发现每次运行程序,输出的结果都不一样,都是一个小于200000的数字。

     

    通过分析字节码我们知道,这是因为volatile只能保证可见性,无法保证原子性,而自增操作并不是一个原子操作(如下图所示),在并发的情况下,putstatic指令可能把较小的race值同步回主内存之中,导致我们每次都无法获得想要的结果。那么,应该怎么解决这个问题了?

     

    解决方法:

    首先我们想到的是用synchronized来修饰increase方法。

     

    使用synchronized修饰后,increase方法变成了一个原子操作,因此是肯定能得到正确的结果。但是,我们知道,每次自增都进行加锁,性能可能会稍微差了点,有更好的方案吗?

     

    答案当然是有的,这个时候我们可以使用Java并发包原子操作类(Atomic开头),例如以下代码。

    我们将例子中的代码稍做修改:race改成使用AtomicInteger定义,“race++”改成使用“race.getAndIncrement()”,AtomicInteger.getAndIncrement()是原子操作,因此我们可以确保每次都可以获得正确的结果,并且在性能上有不错的提升(针对本例子,在JDK1.8.0_151下运行)。

     

    通过方法调用,我们可以发现,getAndIncrement方法调用getAndAddInt方法,最后调用的是compareAndSwapInt方法,即本文的主角CAS,接下来我们开始介绍CAS。

    getAndAddInt方法解析:拿到内存位置的最新值v,使用CAS尝试修将内存位置的值修改为目标值v+delta,如果修改失败,则获取该内存位置的新值v,然后继续尝试,直至修改成功。

     

    CAS是什么?

    CAS是英文单词CompareAndSwap的缩写,中文意思是:比较并替换。CAS需要有3个操作数:内存地址V,旧的预期值A,即将要更新的目标值B。

    CAS指令执行时,当且仅当内存地址V的值与预期值A相等时,将内存地址V的值修改为B,否则就什么都不做。整个比较并替换的操作是一个原子操作。

     

    源码分析

    上面源码分析时,提到最后调用了compareAndSwapInt方法,接着继续深入探讨该方法,该方法在Unsafe中对应的源码如下。

    可以看到调用了“Atomic::cmpxchg”方法,“Atomic::cmpxchg”方法在linux_x86和windows_x86的实现如下。

    linux_x86的实现:

    windows_x86的实现:

    Atomic::cmpxchg方法解析:

    mp是“os::is_MP()”的返回结果,“os::is_MP()”是一个内联函数,用来判断当前系统是否为多处理器。

    1. 如果当前系统是多处理器,该函数返回1。
    2. 否则,返回0。

    LOCK_IF_MP(mp)会根据mp的值来决定是否为cmpxchg指令添加lock前缀。

    1. 如果通过mp判断当前系统是多处理器(即mp值为1),则为cmpxchg指令添加lock前缀。
    2. 否则,不加lock前缀。

    这是一种优化手段,认为单处理器的环境没有必要添加lock前缀,只有在多核情况下才会添加lock前缀,因为lock会导致性能下降。cmpxchg是汇编指令,作用是比较并交换操作数。

     

    intel手册对lock前缀的说明如下:

    1. 确保对内存的读-改-写操作原子执行。在Pentium及Pentium之前的处理器中,带有lock前缀的指令在执行期间会锁住总线,使得其他处理器暂时无法通过总线访问内存。很显然,这会带来昂贵的开销。从Pentium 4,Intel Xeon及P6处理器开始,intel在原有总线锁的基础上做了一个很有意义的优化:如果要访问的内存区域(area of memory)在lock前缀指令执行期间已经在处理器内部的缓存中被锁定(即包含该内存区域的缓存行当前处于独占或以修改状态),并且该内存区域被完全包含在单个缓存行(cache line)中,那么处理器将直接执行该指令。由于在指令执行期间该缓存行会一直被锁定,其它处理器无法读/写该指令要访问的内存区域,因此能保证指令执行的原子性。这个操作过程叫做缓存锁定(cache locking),缓存锁定将大大降低lock前缀指令的执行开销,但是当多处理器之间的竞争程度很高或者指令访问的内存地址未对齐时,仍然会锁住总线。
    2. 禁止该指令与之前和之后的读和写指令重排序。
    3. 把写缓冲区中的所有数据刷新到内存中。

    上面的第1点保证了CAS操作是一个原子操作,第2点和第3点所具有的内存屏障效果,保证了CAS同时具有volatile读和volatile写的内存语义。

     

    CAS的缺点:

    CAS虽然很高效的解决了原子操作问题,但是CAS仍然存在三大问题。

    1. 循环时间长开销很大。
    2. 只能保证一个变量的原子操作。
    3. ABA问题。

     

    循环时间长开销很大:

    CAS 通常是配合无限循环一起使用的,我们可以看到 getAndAddInt 方法执行时,如果 CAS 失败,会一直进行尝试。如果 CAS 长时间一直不成功,可能会给 CPU 带来很大的开销。

     

    只能保证一个变量的原子操作:

    当对一个变量执行操作时,我们可以使用循环 CAS 的方式来保证原子操作,但是对多个变量操作时,CAS 目前无法直接保证操作的原子性。但是我们可以通过以下两种办法来解决:1)使用互斥锁来保证原子性;2)将多个变量封装成对象,通过 AtomicReference 来保证原子性

     

    什么是ABA问题?ABA问题怎么解决?

    CAS 的使用流程通常如下:1)首先从地址 V 读取值 A;2)根据 A 计算目标值 B;3)通过 CAS 以原子的方式将地址 V 中的值从 A 修改为 B。

    但是在第1步中读取的值是A,并且在第3步修改成功了,我们就能说它的值在第1步和第3步之间没有被其他线程改变过了吗?

    如果在这段期间它的值曾经被改成了B,后来又被改回为A,那CAS操作就会误认为它从来没有被改变过。这个漏洞称为CAS操作的“ABA”问题。Java并发包为了解决这个问题,提供了一个带有标记的原子引用类“AtomicStampedReference”,它可以通过控制变量值的版本来保证CAS的正确性。因此,在使用CAS前要考虑清楚“ABA”问题是否会影响程序并发的正确性,如果需要解决ABA问题,改用传统的互斥同步可能会比原子类更高效。

     

    另外,我还准备了很多大厂面试资料、0基础自学教程,由于不能放外链,所以有需要的小伙伴去公众号【程序员囧辉】回复【资料】自行获取好了。

    展开全文
  • CAS原理分析

    万次阅读 多人点赞 2019-04-18 21:41:00
    CAS的英文为Compare and Swap 翻译为比较并交换。 CAS加volatile关键字是实现并发包的基石。没有CAS就不会有并发包,synchronized是一种独占锁、悲观锁,java.util.concurrent中借助了CAS指令实现了一种区别于...

    CAS的英文为Compare and Swap 翻译为比较并交换。

    CAS加volatile关键字是实现并发包的基石。没有CAS就不会有并发包,synchronized是一种独占锁、悲观锁,java.util.concurrent中借助了CAS指令实现了一种区别于synchronized的一种乐观锁。

    什么是乐观锁与悲观锁?

    悲观锁:总是假设最坏的情况,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样当第二个线程想拿这个数据的时候,第二个线程会一直堵塞,直到第一个释放锁,他拿到锁后才可以访问。传统的数据库里面就用到了这种锁机制,例如:行锁,表锁,读锁,写锁,都是在操作前先上锁。java中的synchronized的实现也是一种悲观锁

    乐观锁:乐观锁概念为,每次拿数据的时候都认为别的线程不会修改这个数据,所以不会上锁,但是在更新的时候会判断一下在此期间别的线程有没有修改过数据,乐观锁适用于读操作多的场景,这样可以提高程序的吞吐量。在Java中java.util.concurrent.atomic包下面的原子变量就是使用了乐观锁的一种实现方式CAS实现。

    乐观锁的实现方式-CAS(Compare and Swap):

    jdk1.5之前锁存在的问题:

    java在1.5之前都是靠synchronized关键字保证同步,synchronized保证了无论哪个线程持有共享变量的锁,都会采用独占的方式来访问这些变量。这种情况下:

    1.在多线程竞争下,加锁、释放锁会导致较多的上下文切换和调度延时,引起性能问题

    2.如果一个线程持有锁,其他的线程就都会挂起,等待持有锁的线程释放锁。

    3.如果一个优先级高的线程等待一个优先级低的线程释放锁,会导致优先级倒置,引起性能风险。

    对比于悲观锁的这些问题,另一个更加有效的锁就是乐观锁。 乐观锁就是:每次不加锁而是假设没有并发冲突去操作同一变量,如果有并发冲突导致失败,则重试直至成功。

    乐观锁:

        乐观锁( Optimistic Locking )在上文已经说过了,其实就是一种思想。相对悲观锁而言,乐观锁假设认为数据一般情况下不会产生并发冲突,所以在数据进行提交更新的时候,才会正式对数据是否产生并发冲突进行检测,如果发现并发冲突了,则让返回用户错误的信息,让用户决定如何去做。

        上面提到的乐观锁的概念中其实已经阐述了它的具体实现细节:主要就是两个步骤:冲突检测和数据更新其实现方式有一种比较典型的就是 Compare and Swap ( CAS )。

    乐观锁的一种典型实现机制(CAS):

    乐观锁主要就是两个步骤:冲突检测和数据更新。当多个线程尝试使用CAS同时更新同一个变量时,只有一个线程可以更新变量的值,其他的线程都会失败,失败的线程并不会挂起,而是告知这次竞争中失败了,并可以再次尝试。

    CAS操作包括三个操作数:需要读写的内存位置(V)、预期原值(A)、新值(B)。如果内存位置与预期原值的A相匹配,那么将内存位置的值更新为新值B。如果内存位置与预期原值的值不匹配,那么处理器不会做任何操作。无论哪种情况,它都会在 CAS 指令之前返回该位置的值。(在 CAS 的一些特殊情况下将仅返回 CAS 是否成功,而不提取当前值。)CAS其实就是一个:我认为位置 V 应该包含值 A;如果包含该值,则将 B 放到这个位置;否则,不要更改该位置,只告诉我这个位置现在的值即可。这其实和乐观锁的冲突检测+数据更新的原理是一样的。

    乐观锁是一种思想,CAS只是这种思想的一种实现方式。

    JAVA对CAS的支持:

    在JDK1.5新增的java.util.concurrent(JUC java并发工具包)就是建立在CAS之上的。相比于synchronized这种堵塞算法,CAS是非堵塞算法的一种常见实现。所以JUC在性能上有了很大的提升。

    下面通过看下并发包中的原子操作类AtomicInteger来看下,如何在不使用锁的情况下保证线程安全,主要看下getAndIncrement方法,相当于i++的操作:

    public class AtomicInteger extends Number implements java.io.Serializable {  
        private volatile int value; 
    
        public final int get() {  
            return value;  
        }  
    
        public final int getAndIncrement() {  
            for (;;) {  
                int current = get();  
                int next = current + 1;  
                if (compareAndSet(current, next))  
                    return current;  
            }  
        }  
    
        public final boolean compareAndSet(int expect, int update) {  
            return unsafe.compareAndSwapInt(this, valueOffset, expect, update);  
        }  
    }

    首先value使用了volatile修饰,这就保证了他的可见性与有序性,getAndIncrement采用CAS操作,每次从内存中读取数据然后将数据进行+1操作,然后对原数据,+1后的结果进行CAS操作,成功的话返回结果,否则重试直到成功为止。其中调用了compareAndSet利用JNI(java navite Interface navite修饰的方法,都是java调用其他语言的方法来实现的)来完成CPU的操作。其中compareAndSwapInt类似如下逻辑:

    if (this == expect) {
         this = update
         return true;
     } else {
         return false;
     }

    this == expect和this = update,这两个步骤是如何保证原子性的呢?

    JAVA实现CAS的原理:

    compareAndSwapInt是借助C来调用CPU底层指令实现的。下面从分析比较常用的CPU(intel x86)来解释CAS的实现原理。下面是sun.misc.Unsafe类的compareAndSwapInt()方法的源代码:

    public final native boolean compareAndSwapInt(Object o, long offset,
                                                   int expected, int x);

    再看下在JDK中依次调用的C++代码为:

    #define LOCK_IF_MP(mp) __asm cmp mp, 0  \
                           __asm je L0      \
                           __asm _emit 0xF0 \
                           __asm L0:
    
    inline jint     Atomic::cmpxchg    (jint     exchange_value, volatile jint*     dest, jint     compare_value) {
      // alternative for InterlockedCompareExchange
      int mp = os::is_MP();
      __asm {
        mov edx, dest
        mov ecx, exchange_value
        mov eax, compare_value
        LOCK_IF_MP(mp)
        cmpxchg dword ptr [edx], ecx
      }
    }

    如上面源代码所示,程序会根据当前处理器的类型来决定是否为cmpxchg指令添加lock前缀。如果程序是在多处理器上运行,就为cmpxchg指令加上lock前缀(lock cmpxchg)。反之,如果程序是在单处理器上运行,就省略lock前缀(单处理器自身会维护单处理器内的顺序一致性,不需要lock前缀提供的内存屏障效果)。

    CAS的缺陷:

    1.ABA问题

    比如说一个线程one从内存位置V中取出A,这时候另一个线程two也从内存中取出A,并且two进行了一些操作变成了B,然后two又将V位置的数据变成A,这时候线程one进行CAS操作发现内存中仍然是A,然后one操作成功。尽管线程one的CAS操作成功,但可能存在潜藏的问题。如下所示:

    现有一个用单向链表实现的堆栈,栈顶为A,这时线程T1已经知道A.next为B,然后希望用CAS将栈顶替换为B: head.compareAndSet(A,B); 在T1执行上面这条指令之前,线程T2介入,将A、B出栈,再pushD、C、A,此时堆栈结构如下图,而对象B此时处于游离状态:

    此时轮到线程T1执行CAS操作,检测发现栈顶仍为A,所以CAS成功,栈顶变为B,但实际上B.next为null,所以此时的情况变为:

    其中堆栈中只有B一个元素,C和D组成的链表不再存在于堆栈中,平白无故就把C、D丢掉了。

    解决方法(AtomicStampedReference 带有时间戳的对象引用):

          从Java1.5开始JDK的atomic包里提供了一个类AtomicStampedReference来解决ABA问题。这个类的compareAndSet方法作用是首先检查当前引用是否等于预期引用,并且当前标志是否等于预期标志,如果全部相等,则以原子方式将该引用和该标志的值设置为给定的更新值。

    public boolean compareAndSet(
                   V      expectedReference,//预期引用
    
                   V      newReference,//更新后的引用
    
                  int    expectedStamp, //预期标志
    
                  int    newStamp //更新后的标志
    )

    2.循环时间长开销大

    自旋CAS(不成功,就一直循环执行,直到成功)如果长时间不成功,会给CPU带来非常大的执行开销。如果JVM能支持处理器提供的pause指令那么效率会有一定的提升,pause指令有两个作用,第一它可以延迟流水线执行指令(de-pipeline),使CPU不会消耗过多的执行资源,延迟的时间取决于具体实现的版本,在一些处理器上延迟时间是零。第二它可以避免在退出循环的时候因内存顺序冲突(memory order violation)而引起CPU流水线被清空(CPU pipeline flush),从而提高CPU的执行效率。

    3.只能保证一个共享变量的原子操作

    当对一个共享变量执行操作时,我们可以使用循环CAS的方式来保证原子操作,但是对多个共享变量操作时,循环CAS就无法保证操作的原子性,这个时候就可以用锁,或者有一个取巧的办法,就是把多个共享变量合并成一个共享变量来操作。比如有两个共享变量i=2,j=a,合并一下ij=2a,然后用CAS来操作ij。从Java1.5开始JDK提供了AtomicReference类来保证引用对象之间的原子性,你可以把多个变量放在一个对象里来进行CAS操作。

    CAS与Synchronized的使用情景:   

        1、对于资源竞争较少(线程冲突较轻)的情况,使用synchronized同步锁进行线程阻塞和唤醒切换以及用户态内核态间的切换操作额外浪费消耗cpu资源;而CAS基于硬件实现,不需要进入内核,不需要切换线程,操作自旋几率较少,因此可以获得更高的性能。

        2、对于资源竞争严重(线程冲突严重)的情况,CAS自旋的概率会比较大,从而浪费更多的CPU资源,效率低于synchronized。

       补充: synchronized在jdk1.6之后,已经改进优化。synchronized的底层实现主要依靠Lock-Free的队列,基本思路是自旋后阻塞,竞争切换后继续竞争锁,稍微牺牲了公平性,但获得了高吞吐量。在线程冲突较少的情况下,可以获得和CAS类似的性能;而线程冲突严重的情况下,性能远高于CAS。

     concurrent包的实现:

    由于java的CAS同时具有 volatile 读和volatile写的内存语义,因此Java线程之间的通信现在有了下面四种方式:

          1. A线程写volatile变量,随后B线程读这个volatile变量。

          2. A线程写volatile变量,随后B线程用CAS更新这个volatile变量。

          3. A线程用CAS更新一个volatile变量,随后B线程用CAS更新这个volatile变量。

          4. A线程用CAS更新一个volatile变量,随后B线程读这个volatile变量。

      Java的CAS会使用现代处理器上提供的高效机器级别原子指令,这些原子指令以原子方式对内存执行读-改-写操作,这是在多处理器中实现同步的关键(从本质上来说,能够支持原子性读-改-写指令的计算机器,是顺序计算图灵机的异步等价机器,因此任何现代的多处理器都会去支持某种能对内存执行原子性读-改-写操作的原子指令)。同时,volatile变量的读/写和CAS可以实现线程之间的通信。把这些特性整合在一起,就形成了整个concurrent包得以实现的基石。如果我们仔细分析concurrent包的源代码实现,会发现一个通用化的实现模式:

          1. 首先,声明共享变量为volatile;  

          2. 然后,使用CAS的原子条件更新来实现线程之间的同步;

          3. 同时,配合以volatile的读/写和CAS所具有的volatile读和写的内存语义来实现线程之间的通信。

    AbstractQueuedSynchronizer(AQS抽象的队列同步器),atomic类,非堵塞数据结构这些concurrent包中的基础类都是使用这种模式实现的,而concurrent包中的高层类又是依赖于这些基础类实现的。concurrent包的整体示意图如下:

    JVM中的CAS(堆中对象的分配): 

         Java调用new object()会创建一个对象,这个对象会被分配到JVM的堆中。那么这个对象到底是怎么在堆中保存的呢?

         首先,new object()执行的时候,这个对象需要多大的空间,其实是已经确定的,因为java中的各种数据类型,占用多大的空间都是固定的(对其原理不清楚的请自行Google)。那么接下来的工作就是在堆中找出那么一块空间用于存放这个对象。 
    在单线程的情况下,一般有两种分配策略:

    1. 指针碰撞:这种一般适用于内存是绝对规整的(内存是否规整取决于内存回收策略),分配空间的工作只是将指针像空闲内存一侧移动对象大小的距离即可。

    2. 空闲列表:这种适用于内存非规整的情况,这种情况下JVM会维护一个内存列表,记录哪些内存区域是空闲的,大小是多少。给对象分配空间的时候去空闲列表里查询到合适的区域然后进行分配即可。

        但是JVM不可能一直在单线程状态下运行,那样效率太差了。由于再给一个对象分配内存的时候不是原子性的操作,至少需要以下几步:查找空闲列表、分配内存、修改空闲列表等等,这是不安全的。解决并发时的安全问题也有两种策略:

    1. CAS:实际上虚拟机采用CAS配合上失败重试的方式保证更新操作的原子性,原理和上面讲的一样。

    2. TLAB:如果使用CAS其实对性能还是会有影响的,所以JVM又提出了一种更高级的优化策略:每个线程在Java堆中预先分配一小块内存,称为本地线程分配缓冲区(TLAB),线程内部需要分配内存时直接在TLAB上分配就行,避免了线程冲突。只有当缓冲区的内存用光需要重新分配内存的时候才会进行CAS操作分配更大的内存空间。 
    虚拟机是否使用TLAB,可以通过-XX:+/-UseTLAB参数来进行配置(jdk5及以后的版本默认是启用TLAB的)。

     

     

    最后送大家一段苹果的广告语,致疯狂的人 

          他们特立独行。他们桀骜不驯。他们惹是生非。他们格格不入。他们用与众不同的眼光看待事物。他们不喜欢墨守成规。他们也不愿安于现状。你可以认同他们,反对他们,颂扬或是诋毁他们。但唯独不能漠视他们。因为他们改变了寻常事物。他们推动人类向前迈进。或许他们是别人眼里的疯子,但他们却是我们眼中的天才。因为只有那些疯狂到以为自己能够改变世界的人,才能真正改变世界。

     

     

     

     

     

     

     

     

     

     

     

     

     

    展开全文
  • 什么是CAS机制?

    万次阅读 多人点赞 2018-07-24 21:59:02
    我们先看一段代码: 启动两个线程,每个线程中让静态变量count循环累加100次。 最终输出的count结果一定是200吗?因为这段代码是非线程安全的,所以最终的自增结果很可能会小于200。我们再加上synchronized同步...
  • JAVA并发编程: CAS和AQS

    万次阅读 多人点赞 2019-11-19 09:40:32
    说起JAVA并发编程,就不得不聊聊CAS(Compare And Swap)和AQS了(AbstractQueuedSynchronizer)。 CAS(Compare And Swap) 什么是CAS CAS(Compare And Swap),即比较并交换。是解决多线程并行...
  • AQS CAS简单详解(写的比较好)

    万次阅读 多人点赞 2017-11-16 16:31:01
    CAS(Compare And Swap) 什么是CAS CAS(Compare And Swap),即比较并交换。是解决多线程并行情况下使用锁造成性能损耗的一种机制,CAS操作包含三个操作数——内存位置(V)、预期原值(A)和新值(B)。如果...
  • JUC(四)CAS和AQS概念

    2019-07-24 20:33:58
    什么是CAS ? CAS 是 compareAndSwap的缩写 比较交换 类似于java中的乐观锁 乐观锁与悲观所的区别在于 – 乐观锁趋向于不加锁来处理资源比如给记录加入version这种方法 记录版本号 他将内存地址的内容和定值相比较 ...
  • java并发编程(CAS和AQS区别) 来个简单的理解: CAS可以理解成一种乐观的自旋锁的机制,实现使用锁时不锁住对象,达到加锁的目的。(乐观锁 和 并发原子类也是利用CAS工具实现的) AQS是一种JAVA底层实现线程...
  • java的CAS和AQS(清晰)

    2019-04-03 09:53:43
    本文转自:... 说起JAVA并发编程,就不得不聊聊CAS(Compare And Swap)和AQS了(AbstractQueuedSynchronizer)。 CAS(Compare And Swap) 什么是CAS CAS(Compare And Swap),即比较并交...
  • CAS实现单点登录

    万次阅读 2019-05-06 16:13:46
    1.简介 SSO单点登录 在多个相互信任的系统中,用户只需要登录一次就可以访问其他受信任的系统。 ...*当用户首次访问新浪微博时,新浪微博识别到用户未登录,将请求重定向到认证中心,认证中心也识别到用户未登录...
  • CAS实现单点登录SSO执行原理探究(终于明白了)

    万次阅读 多人点赞 2017-01-04 18:22:13
    CAS框架:CAS(Central Authentication Service)是实现SSO单点登录的框架。2、盗一张学习CAS绝大多都看过的图以及执行部分分析注:已分不清原创,此处就不给出地址了。 从结构上看,CAS包含两个部分:C
  • JAVA CAS原理深度分析

    万次阅读 多人点赞 2013-07-25 13:07:33
    看了一堆文章,终于把JAVA CAS的原理深入分析清楚了。 感谢GOOGLE强大的搜索,借此挖苦下百度,依靠百度什么都学习不到!   参考文档: http://www.blogjava.net/xylz/archive/2010/07/04/325206.html ...
  • CAS(一)搭建CAS - server服务器

    万次阅读 多人点赞 2018-11-21 13:45:26
    CAS 5.2 tomcat 8+ about CAS cas document https://apereo.github.io/cas/5.2.x/index.html cas server 客户端模板下载 https://github.com/apereo/cas-overlay-template   步骤 一、修改hosts文件,模拟...
  • cas 4.0——cas的新版本可以下载了

    万次阅读 2014-06-22 21:09:42
    http://www.jasig.org/cas可以下载cas4.0,初看起来没有什么变化,但是代码结构变化太大,
  • Apache Shiro 集成-Cas

    万次阅读 热门讨论 2013-04-19 16:38:32
    Shiro集成CAS是在1.2版本里新增的功能。 Shiro-cas模块将应用作为CAS客户端与CAS SSO服务器一起保护web应用。 CAS协议的一个基本理解: 1. 如果你想访问一个被CAS客户端保护的应用,而你还没有进行认证。你讲...
  • CAS实现SSO单点登录-CAS Server搭建

    万次阅读 2018-07-14 17:03:12
    最近公司连续接了三四个单点登录集成的项目,由我们公司提供CAS Server端的,也有需要我们把Client与其他公司提供的Server端对接的,我负责把我们公司的一个Client与另外一个公司提供的Server端对接,由于
  • CAS4.2.7作为服务端,配置CAS客户端,用tomcat作服务器,由客户端跳转到CAS服务端时出错下面错误提示 CAS 未认证授权服务 不允许使用CAS来认证您访问的目标应用 跳转的URL是这样的: ...
  • CAS原理与协议

    万次阅读 2014-06-29 19:57:58
    SSO英文全称Single Sign On,...SSO的解决方案很多,比如收费的有UTrust、惠普灵动等,开源的有CAS、Smart SSO等,其中应用最为广泛的是CASCAS (Central Authentication Service)中央认证服务。CAS(Central Auth
  • cas-server-support-rest子项目有什么用:如果一个android app要接入cas中心系统,就需要用到这个子项目。 引入的前提条件是,cas项目已经启用了,通常不会启用一部分项目,如cas-server-webapp。 引入步骤: 1、将...
1 2 3 4 5 ... 20
收藏数 157,399
精华内容 62,959
关键字:

cas