使用Spring Security 集成 CAS 完成單點(diǎn)登錄

一、企業(yè)單一登錄(CAS)

1.Java(Spring Webflow / MVC servlet)服務(wù)器組件

2.可插拔認(rèn)證支持(LDAP,數(shù)據(jù)庫(kù)丑掺,X.509,雙因素)

3.支持多種協(xié)議(CAS述雾,SAML街州,OAuth,OpenID)

4.跨平臺(tái)的客戶(hù)端支持(Java玻孟,.Net唆缴,PHP,Perl黍翎,Apache等)

5.與uPortal面徽,Liferay,BlueSocket,Moodle和Google Apps集成趟紊,僅舉幾例

CAS提供了一個(gè)友好的開(kāi)源社區(qū)氮双,積極支持和貢獻(xiàn)項(xiàng)目。雖然該項(xiàng)目植根于更高級(jí)的開(kāi)放源代碼霎匈,但已經(jīng)發(fā)展成為世界500強(qiáng)企業(yè)和小型專(zhuān)用設(shè)施的國(guó)際用戶(hù)戴差。

二、如何部署您的CAS

在項(xiàng)目中安裝CAS服務(wù)器铛嘱,需要去官方github下載CAS標(biāo)準(zhǔn)WAR文件暖释,在WAR文件中有標(biāo)準(zhǔn)的單點(diǎn)登錄登出頁(yè)面。當(dāng)然您還需要對(duì)deployerConfigContext.xml中指定AuthenticationHandler進(jìn)行簡(jiǎn)單的修改墨吓,已滿(mǎn)足您對(duì)數(shù)據(jù)庫(kù)的操作需求球匕。CAS 本身包含大量的AuthenticationHandler,可以協(xié)助解決相應(yīng)的問(wèn)題帖烘。

除CAS服務(wù)器本身之外亮曹,其他關(guān)鍵角色當(dāng)然是在企業(yè)中部署的安全Web應(yīng)用程序,這些Web應(yīng)用程序被稱(chēng)為“服務(wù)“蚓让。有三種類(lèi)型的服務(wù):驗(yàn)證服務(wù)票據(jù)乾忱,獲得代理票據(jù),驗(yàn)證代理票據(jù)历极。驗(yàn)證代理票據(jù)的不同之處在于代理列表必須經(jīng)過(guò)驗(yàn)證,并且通持缘瑁可以重用代理趟卸。

CAS本身設(shè)計(jì)在HTTPS環(huán)境下,在本地測(cè)試以及個(gè)人學(xué)習(xí)情況下可以對(duì)CAS做些相應(yīng)修改氏义,使它支持HTTP訪問(wèn)锄列。在CAS的WAR文件目錄:WEB-INF\classes\services下修改HTTPSandIMAPS-10000001.json配置文件,將serviceId屬性的值修改為:

"serviceId":"^(https|imaps|http)://.*"

在CAS 4.2版本后惯悠,CAS的所有配置都放在cas.properties文件中邻邮,所以為了可以自定義cas.properties的路徑,您可以修改WEB-INF\spring-configuration\propertyFileConfigurer.xml文件中的:

<util:properties id="casProperties" location="classpath:cas.properties" />

為了讓CAS能夠通過(guò)數(shù)據(jù)庫(kù)鑒定用戶(hù)憑證克婶,需要配置Database Authentication筒严。官方文檔詳見(jiàn):https://apereo.github.io/cas/4.2.x/installation/Database-Authentication.html。數(shù)據(jù)庫(kù)認(rèn)證有四種:

1.QueryDatabaseAuthenticationHandler情萤,通過(guò)用戶(hù)名和明文密碼進(jìn)行驗(yàn)證鸭蛙。
首先在cas.properties中配置:
# cas.jdbc.authn.query.sql=select password from users where username=?
在deployerConfigContext.xml中配置
<alias name="queryDatabaseAuthenticationHandler" alias="primaryAuthenticationHandler" />
<alias name="dataSource" alias="queryDatabaseDataSource" />

2.SearchModeSearchDatabaseAuthenticationHandler,通過(guò)查詢(xún)用戶(hù)名和密碼來(lái)搜索用戶(hù)記錄; 如果至少有一個(gè)結(jié)果被發(fā)現(xiàn)筋岛,用戶(hù)將被認(rèn)證娶视。
首先在cas.properties中配置
# cas.jdbc.authn.search.password=
# cas.jdbc.authn.search.user=
# cas.jdbc.authn.search.table=
在deployerConfigContext.xml中配置
<alias name="searchModeSearchDatabaseAuthenticationHandler" alias="primaryAuthenticationHandler" />
<alias name="dataSource" alias="searchModeDatabaseDataSource" />

 3.BindModeSearchDatabaseAuthenticationHandler,嘗試使用用戶(hù)名和(散列)密碼創(chuàng)建數(shù)據(jù)庫(kù)連接來(lái)對(duì)用戶(hù)進(jìn)行身份驗(yàn)證。
在deployerConfigContext.xml中配置
<alias name="bindModeSearchDatabaseAuthenticationHandler" alias="primaryAuthenticationHandler" />
<alias name="dataSource" alias="bindSearchDatabaseDataSource" />

4.QueryAndEncodeDatabaseAuthenticationHandler肪获,一個(gè)JDBC查詢(xún)處理程序寝凌,它將撤回用戶(hù)的密碼和私有salt值,并使用公共salt值驗(yàn)證編碼的密碼孝赫。 假設(shè)一切都在同一個(gè)數(shù)據(jù)庫(kù)表內(nèi)硫兰。 支持迭代次數(shù)和私鹽的設(shè)置。
首先在cas.properties中配置
# cas.jdbc.authn.query.encode.sql=
# cas.jdbc.authn.query.encode.alg=
# cas.jdbc.authn.query.encode.salt.static=
# cas.jdbc.authn.query.encode.password=表字段名
# cas.jdbc.authn.query.encode.salt=表字段名
# cas.jdbc.authn.query.encode.iterations.field=表字段名
# cas.jdbc.authn.query.encode.iterations=
在deployerConfigContext.xml中配置
<alias name="queryAndEncodeDatabaseAuthenticationHandler" alias="primaryAuthenticationHandler" />
<alias name="dataSource" alias="queryEncodeDatabaseDataSource" />

一般選擇第四種數(shù)據(jù)認(rèn)證方式寒锚,修改完成后丟到tomcat下運(yùn)行即可劫映。
cas的訪問(wèn)地址:ip:port/cas/login
cas的登出地址:ip:port/cas/logout

三、Spring Security和CAS的集成

Web瀏覽器刹前,CAS服務(wù)器和Spring安全服務(wù)之間的基本交互如下:

CAS或Spring Security不管理公共頁(yè)面的處理泳赋,當(dāng)用戶(hù)請(qǐng)求一個(gè)安全的頁(yè)面或者它使用的一個(gè)安全的頁(yè)面。 Spring Security的ExceptionTranslationFilter將檢測(cè)到AccessDeniedException或AuthenticationException喇喉。

由于用戶(hù)的Authentication對(duì)象(或缺少)導(dǎo)致AuthenticationException祖今,因此ExceptionTranslationFilter將調(diào)用已配置的AuthenticationEntryPoint。如果使用CAS拣技,這將是CasAuthenticationEntryPoint類(lèi)千诬。

CasAuthenticationEntryPoint將把用戶(hù)的瀏覽器重定向到CAS服務(wù)器。它還會(huì)顯示一個(gè)服務(wù)參數(shù)膏斤,它是Spring Security服務(wù)(您的應(yīng)用程序)的回調(diào)URL徐绑。例如,瀏覽器重定向到的URL可能是

https://my.company.com/cas/login莫辨?service= HTTPS%3A%2F%2Fserver3.company.com%2Fwebapp%2Flogin / CAS傲茄。

用戶(hù)的瀏覽器重定向到CAS后液走,系統(tǒng)會(huì)提示用戶(hù)輸入用戶(hù)名和密碼坚冀。如果用戶(hù)提交了一個(gè)表示他們以前登錄過(guò)的會(huì)話cookie炕桨,他們將不會(huì)再被提示重新登錄(這個(gè)過(guò)程是個(gè)例外儡循,我們將在后面介紹)凑保。 CAS將使用上述的PasswordHandler(或使用CAS 3.0的AuthenticationHandler)來(lái)決定用戶(hù)名和密碼是否有效姐仅。

CAS成功登錄后唯卖,會(huì)將用戶(hù)瀏覽器重定向到原始服務(wù)眠寿。它還將包含一個(gè)票據(jù)參數(shù)型酥,這是一個(gè)不透明的字符串山憨,代表“服務(wù)票據(jù)”。繼續(xù)前面的例子冕末,瀏覽器被重定向到的URL可能是

https://server3.company.com/webapp/login/cas?ticket=ST-0-ER94xMJmn6pha35CQRoZ萍歉。

回到服務(wù)Web應(yīng)用程序,CasAuthenticationFilter總是監(jiān)聽(tīng)/ login / cas的請(qǐng)求(這是可配置的档桃,但是我們將使用這個(gè)介紹中的默認(rèn)值)枪孩。處理過(guò)濾器將構(gòu)建代表服務(wù)票據(jù)的UsernamePasswordAuthenticationToken。主體將等于CasAuthenticationFilter.CAS_STATEFUL_IDENTIFIER,而憑證將是服務(wù)票證不透明值蔑舞。這個(gè)認(rèn)證請(qǐng)求將被交給配置的AuthenticationManager拒担。

AuthenticationManager實(shí)現(xiàn)將是ProviderManager,它又被配置了CasAuthenticationProvider攻询。 CasAuthenticationProvider只響應(yīng)包含CAS特定主體(如CasAuthenticationFilter.CAS_STATEFUL_IDENTIFIER)和CasAuthenticationToken(稍后討論)的UsernamePasswordAuthenticationToken从撼。

CasAuthenticationProvider將使用TicketValidator實(shí)現(xiàn)來(lái)驗(yàn)證服務(wù)票證。這通常是一個(gè)Cas20ServiceTicketValidator钧栖,它是包含在CAS客戶(hù)端庫(kù)中的一個(gè)類(lèi)低零。如果應(yīng)用程序需要驗(yàn)證代理票證,則使用Cas20ProxyTicketValidator拯杠。 TicketValidator向CAS服務(wù)器發(fā)出HTTPS請(qǐng)求掏婶,以驗(yàn)證服務(wù)票據(jù)。它也可能包含一個(gè)代理回調(diào)URL潭陪,它包含在這個(gè)例子中:

https://my.company.com/cas/proxyValidate?service=https%3A%2F%2Fserver3.company.com%2Fwebapp%2Flogin/cas&ticket= ST-0-ER94xMJmn6pha35CQRoZ&pgtUrl = HTTPS://server3.company.com/webapp/login/cas/proxyreceptor雄妥。

回到CAS服務(wù)器,驗(yàn)證請(qǐng)求將被接收依溯。如果所提供的服務(wù)票據(jù)與發(fā)行票據(jù)的服務(wù)URL相匹配老厌,則CAS將以XML表示用戶(hù)名的肯定響應(yīng)。如果任何代理參與了身份驗(yàn)證(如下所述)黎炉,那么代理列表也會(huì)包含在XML響應(yīng)中枝秤。

[可選]如果對(duì)CAS驗(yàn)證服務(wù)的請(qǐng)求包含代理回調(diào)URL(在pgtUrl參數(shù)中),則CAS將在XML響應(yīng)中包含一個(gè)pgtIou字符串拜隧。這pgtIou代表代理授予票借條宿百。然后,CAS服務(wù)器將創(chuàng)建自己的HTTPS連接回pgtUrl洪添。這是為了相互認(rèn)證CAS服務(wù)器和聲稱(chēng)的服務(wù)URL。 HTTPS連接將用于將授權(quán)票據(jù)的代理發(fā)送到原始Web應(yīng)用程序雀费。例如干奢,

  https://server3.company.com/webapp/login/cas/proxyreceptor?pgtIou=PGTIOU-0-R0zlgrl4pdAQwBvJWO3vnNpevwqStbSGcq3vKB2SqSFFRnjPHt&pgtId=PGT-1-si9YkkHLrtACBo64rmsi3v2nf7cpCResXg5MpESZFArbaZiOKH。

Cas20TicketValidator將解析從CAS服務(wù)器收到的XML盏袄。它將返回CasAuthenticationProvider TicketResponse忿峻,其中包括用戶(hù)名(強(qiáng)制),代理列表(如果有任何涉及)辕羽,和代理授予票證IOU(如果代理回調(diào)被請(qǐng)求)逛尚。

接下來(lái),CasAuthenticationProvider將調(diào)用已配置的CasProxyDecider刁愿。 CasProxyDecider指示TicketResponse中的代理列表是否可以被服務(wù)接受绰寞。 Spring Security提供了幾個(gè)實(shí)現(xiàn):RejectProxyTickets,AcceptAnyCasProxy和NamedCasProxyDecider。這些名稱(chēng)在很大程度上是不言而喻的滤钱,除了NamedCasProxyDecider允許提供可信代理列表觉壶。

CasAuthenticationProvider接下來(lái)將請(qǐng)求一個(gè)AuthenticationUserDetailsS??ervice來(lái)加載適用于Assertion中包含的用戶(hù)的GrantedAuthority對(duì)象。
如果沒(méi)有問(wèn)題件缸,CasAuthenticationProvider構(gòu)造一個(gè)CasAuthenticationToken铜靶,包括TicketResponse和GrantedAuthoritys中包含的細(xì)節(jié)。

控制然后返回到CasAuthenticationFilter他炊,它將創(chuàng)建的CasAuthenticationToken放置在安全上下文中争剿。

用戶(hù)的瀏覽器被重定向到導(dǎo)致AuthenticationException的原始頁(yè)面(或根據(jù)配置的自定義目標(biāo))。

四痊末、Spring Boot +Spring Security+CAS開(kāi)發(fā)(代理票據(jù)認(rèn)證)

CasAuthenticationProvider區(qū)分有狀態(tài)和無(wú)狀態(tài)客戶(hù)端蚕苇。 有狀態(tài)的客戶(hù)端被認(rèn)為是提交給CasAuthenticationFilter的filterProcessUrl的。 無(wú)狀態(tài)客戶(hù)端是指向除FilterProcessUrl以外的URL向CasAuthenticationFilter提交身份驗(yàn)證請(qǐng)求的任何客戶(hù)端舌胶。

由于遠(yuǎn)程協(xié)議無(wú)法在HttpSession的上下文中呈現(xiàn)捆蜀,因此不可能依賴(lài)于在請(qǐng)求之間的會(huì)話中存儲(chǔ)安全上下文的默認(rèn)實(shí)踐。 此外幔嫂,由于CAS服務(wù)器在TicketValidator驗(yàn)證之后使其無(wú)效辆它,因此在后續(xù)請(qǐng)求中顯示相同的代理票證將不起作用。

CasConfing配置:
//客戶(hù)端配置
public static String casServiceHost="http://127.0.0.1:8080";
public static String casServiceLogin=casServiceHost+"/login/cas";
public static String casServiceLogout=casServiceHost+"/logout/cas";
public static String casServiceProxyCallbackUrl="/login/cas/proxyreceptor";
public static String casServiceFailureHandler="/cas/casfailed";

//cas服務(wù)端配置
@Value("${cas.server.host:http://127.0.0.1:8081/cas}")
public static String casServerUrlPrefix="http://127.0.0.1:8081/cas";
public static String casServerUrlLogin=casServerUrlPrefix+"/login";
public static String casServerUrlLogout=casServerUrlPrefix+"/logout";

@Autowired
public static ProxyGrantingTicketStorageImpl pgtStorage;

@Bean
public ServiceProperties serviceProperties(){
    ServiceProperties serviceProperties=new ServiceProperties();
    serviceProperties.setService(casServiceLogin);
    serviceProperties.setAuthenticateAllArtifacts(true);
    return serviceProperties;
}

@Bean
public CasAuthenticationEntryPoint casAuthenticationEntryPoint(@Qualifier("serviceProperties") ServiceProperties serviceProperties){
    CasAuthenticationEntryPoint entryPoint=new CasAuthenticationEntryPoint();
    entryPoint.setServiceProperties(serviceProperties);
    entryPoint.setLoginUrl(casServerUrlLogin);

    return entryPoint;
}

@Bean("pgtStorage")
public ProxyGrantingTicketStorageImpl proxyGrantingTicketStorageImpl(){
    return new ProxyGrantingTicketStorageImpl();
}

@Bean("casAuthenticationProvider")
public CasAuthenticationProvider casAuthenticationProvider(@Qualifier("serviceProperties") ServiceProperties serviceProperties,
        @Qualifier("customCasUserDetailsService") CustomCasUserDetailsService customCasUserDetailsService){
    CasAuthenticationProvider authenticationProvider=new CasAuthenticationProvider();
    authenticationProvider.setKey("casProvider") ;
    authenticationProvider.setServiceProperties(serviceProperties);
    Cas20ProxyTicketValidator ticketValidator=new Cas20ProxyTicketValidator(casServerUrlPrefix);
    ticketValidator.setAcceptAnyProxy(true);//允許所有代理回調(diào)鏈接
    ticketValidator.setProxyGrantingTicketStorage(pgtStorage);
    authenticationProvider.setTicketValidator(ticketValidator);
    authenticationProvider.setAuthenticationUserDetailsService(customCasUserDetailsService);
    //無(wú)狀態(tài)緩存
    EhCacheBasedTicketCache ticketCache=new EhCacheBasedTicketCache();
    ticketCache.setCache(new Cache("casTickets", 50, true, false, 3600, 900));
    authenticationProvider.setStatelessTicketCache(ticketCache);
    
    return authenticationProvider;
}

//單點(diǎn)登出履恩,跳轉(zhuǎn)到客戶(hù)端的登出鏈接
@Bean("requestSingleLogoutFilter")
public LogoutFilter logoutFilter() {
    LogoutFilter logoutFilter = new LogoutFilter(casServerUrlLogout, new SecurityContextLogoutHandler());
    logoutFilter.setFilterProcessesUrl(casServiceLogout);
    return logoutFilter;
}

WebSecurityCasConfig配置:

    @Autowired
CasAuthenticationProvider casAuthenticationProvider;

@Autowired
CasAuthenticationEntryPoint casAuthenticationEntryPoint;

@Autowired
LogoutFilter requestSingleLogoutFilter;

@Autowired
ServiceProperties serviceProperties;
    
public CasAuthenticationFilter casAuthenticationFilter() throws Exception{
    CasAuthenticationFilter casAuthenticationFilter=new CasAuthenticationFilter();
    casAuthenticationFilter.setAuthenticationManager(authenticationManager());
    casAuthenticationFilter.setServiceProperties(serviceProperties);
    casAuthenticationFilter.setProxyGrantingTicketStorage(CasConfing.pgtStorage);
    casAuthenticationFilter.setProxyReceptorUrl(CasConfing.casServiceProxyCallbackUrl);
    casAuthenticationFilter.setAuthenticationDetailsSource(new ServiceAuthenticationDetailsSource(serviceProperties));
    casAuthenticationFilter.setAuthenticationFailureHandler(new SimpleUrlAuthenticationFailureHandler(CasConfing.casServiceFailureHandler));

    return casAuthenticationFilter;
}

@Override
protected void configure(HttpSecurity http) throws Exception {
    // TODO Auto-generated method stub
    http
    .authorizeRequests()
    .antMatchers("/cas/casfailed").permitAll()
    .antMatchers("/secure/extreme/").access("hasRole('ROLE_SUPERVISOR')")
    .antMatchers("/secure/**").access("hasRole('ROLE_USER')")
    .anyRequest().authenticated()
    .and()
    .logout()
    .logoutUrl("/logout/cas")
    .logoutSuccessUrl(CasConfing.casServerUrlLogout+"?service="+CasConfing.casServiceHost+"/index")
    .permitAll()
    .and()
    .csrf().disable();

    //CAS服務(wù)器的單點(diǎn)登錄
    SingleSignOutFilter singleSignOutFilter = new SingleSignOutFilter();
    singleSignOutFilter.setCasServerUrlPrefix(CasConfing.casServerUrlPrefix);
    http
    .exceptionHandling().authenticationEntryPoint(casAuthenticationEntryPoint)
    .and()
    .addFilter(casAuthenticationFilter())
    .addFilterBefore(requestSingleLogoutFilter, LogoutFilter.class)
    .addFilterBefore(singleSignOutFilter, CasAuthenticationFilter.class);
}


@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    // TODO Auto-generated method stub
    auth.authenticationProvider(casAuthenticationProvider);
    super.configure(auth);
}

CustomCasUserDetailsService自定義認(rèn)證用戶(hù)信息處理配置:

@Service

public class CustomCasUserDetailsService implements AuthenticationUserDetailsService<CasAssertionAuthenticationToken>{

@Override
public UserDetails loadUserDetails(CasAssertionAuthenticationToken token) throws UsernameNotFoundException {
    // TODO Auto-generated method stub
    System.err.println("當(dāng)前認(rèn)證成功的用戶(hù)名:"+token.getName());
    List<GrantedAuthority> grantedAuthorities = new ArrayList<>();
    GrantedAuthority grantedAuthority=new SimpleGrantedAuthority("ROLE_SUPERVISOR");
    grantedAuthorities.add(grantedAuthority);
    grantedAuthority=new SimpleGrantedAuthority("ROLE_USER");
    grantedAuthorities.add(grantedAuthority);
    
    return new User(token.getName(), "a52302c58f4a60f49b1ad2f36add6d0a-000000", grantedAuthorities);
}

}

至此锰茉,Spring Security+CAS集成配置以完成。

您可以通過(guò)訪問(wèn)客戶(hù)端Security安全頁(yè)面:
http://127.0.0.1:8080/index,
security會(huì)轉(zhuǎn)到CAS服務(wù)器登錄鏈接
http://127.0.0.1:8081/cas/login?service=http%3A%2F%2F127.0.0.1%3A8080%2Flogin%2Fcas
登錄認(rèn)證通過(guò)后即可訪問(wèn)安全頁(yè)面切心。

多站點(diǎn):
分別部署兩個(gè)站點(diǎn):serviceCas01,serviceCas02
 http://127.0.0.1:8080/serviceCas01/index,
 http://127.0.0.1:8082/serviceCas02/index,
serviceCas01登錄認(rèn)證成功后飒筑,直接通過(guò)訪問(wèn)  http://127.0.0.1:8082/serviceCas02/index,即可無(wú)需登錄訪問(wèn)。通過(guò)http://127.0.0.1:8080/serviceCas01/logout/cas成功登出后绽昏,  重新刷新頁(yè)面http://127.0.0.1:8082/serviceCas02/index,也會(huì)登出协屡。

后續(xù)有時(shí)間,再配圖啦全谤。不足之處肤晓,謝謝指教。

銘言:  
        吾等前方认然,再無(wú)對(duì)手
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末补憾,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子卷员,更是在濱河造成了極大的恐慌盈匾,老刑警劉巖,帶你破解...
    沈念sama閱讀 207,113評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件毕骡,死亡現(xiàn)場(chǎng)離奇詭異削饵,居然都是意外死亡岩瘦,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評(píng)論 2 381
  • 文/潘曉璐 我一進(jìn)店門(mén)葵孤,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)担钮,“玉大人,你說(shuō)我怎么就攤上這事尤仍◇锝颍” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 153,340評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵宰啦,是天一觀的道長(zhǎng)苏遥。 經(jīng)常有香客問(wèn)我,道長(zhǎng)赡模,這世上最難降的妖魔是什么田炭? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,449評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮漓柑,結(jié)果婚禮上教硫,老公的妹妹穿的比我還像新娘。我一直安慰自己辆布,他們只是感情好瞬矩,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,445評(píng)論 5 374
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著锋玲,像睡著了一般景用。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上惭蹂,一...
    開(kāi)封第一講書(shū)人閱讀 49,166評(píng)論 1 284
  • 那天伞插,我揣著相機(jī)與錄音,去河邊找鬼盾碗。 笑死媚污,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的廷雅。 我是一名探鬼主播杠步,決...
    沈念sama閱讀 38,442評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼榜轿!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起朵锣,我...
    開(kāi)封第一講書(shū)人閱讀 37,105評(píng)論 0 261
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤谬盐,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后诚些,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體飞傀,經(jīng)...
    沈念sama閱讀 43,601評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡皇型,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,066評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了砸烦。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片弃鸦。...
    茶點(diǎn)故事閱讀 38,161評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖幢痘,靈堂內(nèi)的尸體忽然破棺而出唬格,到底是詐尸還是另有隱情,我是刑警寧澤颜说,帶...
    沈念sama閱讀 33,792評(píng)論 4 323
  • 正文 年R本政府宣布购岗,位于F島的核電站,受9級(jí)特大地震影響门粪,放射性物質(zhì)發(fā)生泄漏喊积。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,351評(píng)論 3 307
  • 文/蒙蒙 一玄妈、第九天 我趴在偏房一處隱蔽的房頂上張望乾吻。 院中可真熱鬧,春花似錦拟蜻、人聲如沸绎签。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,352評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)辜御。三九已至,卻和暖如春屈张,著一層夾襖步出監(jiān)牢的瞬間擒权,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,584評(píng)論 1 261
  • 我被黑心中介騙來(lái)泰國(guó)打工阁谆, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留碳抄,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,618評(píng)論 2 355
  • 正文 我出身青樓场绿,卻偏偏與公主長(zhǎng)得像剖效,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子焰盗,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,916評(píng)論 2 344

推薦閱讀更多精彩內(nèi)容

  • 1. CAS 簡(jiǎn)介 1.1. What is CAS 璧尸? CAS ( Central Authenti...
    人在碼途閱讀 9,806評(píng)論 3 51
  • 簡(jiǎn)介 Cas介紹 CAS ( Central Authentication Service ),最初由耶魯大學(xué)的S...
    但莫閱讀 14,619評(píng)論 0 10
  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理熬拒,服務(wù)發(fā)現(xiàn)爷光,斷路器,智...
    卡卡羅2017閱讀 134,601評(píng)論 18 139
  • 以下是官網(wǎng)直譯:https://oauth.net/ 1. 首頁(yè) OAuth是一種開(kāi)放協(xié)議(注:協(xié)議是公開(kāi)的澎粟,任何...
    KennethChen93閱讀 11,187評(píng)論 0 20
  • [00:10.00]Lyrics by @MPlover [00:22.45]connection [00:24....
    猴大貓閱讀 192評(píng)論 0 0