SSO單點(diǎn)登錄------源碼分析

4 源碼解析

4.1 Server源碼解析

Cas server端采用Spring WebFlow來(lái)進(jìn)行流程控制,因此本文以系統(tǒng)webflow文件為切入點(diǎn),對(duì)流程相關(guān)源碼進(jìn)行分析。Cas系統(tǒng)的webflow文件位于WEB-INF/webflow目錄下,分為登陸流程和登出流程。

4.1.1 登陸流程解析
4.1.1.1 訪問(wèn)接入Cas系統(tǒng)的應(yīng)用系統(tǒng)Client1

登陸流程配置文件為login-webflow.xm。
瀏覽器首次訪問(wèn)配置了單點(diǎn)登錄的應(yīng)用系統(tǒng)時(shí)(http://www.client1.com/index),Client1會(huì)將請(qǐng)求重定向到cas系統(tǒng)
(http://www.casserver.com/serviceValidate?service=http://www.client1.com/index)
cas系統(tǒng)接收到瀏覽器發(fā)來(lái)的請(qǐng)求,整個(gè)登錄流程從此處開(kāi)始,流程初始化。
WEB-INF/login-webflow.xml部分代碼:

 <on-start>
        <evaluate expression="initialFlowSetupAction"/>
    </on-start>

初始化部分會(huì)調(diào)用InitialFlowSetupAction類的doExecute方法,如果有特殊需求,可以在此方法中增加相應(yīng)的邏輯。
InitialFlowSetupAction的doExecute方法:

@Override
    protected Event doExecute(final RequestContext context) throws Exception {
        final HttpServletRequest request = WebUtils.getHttpServletRequest(context);

        final String contextPath = context.getExternalContext().getContextPath();
        final String cookiePath = StringUtils.isNotBlank(contextPath) ? contextPath + '/' : "/";

        if (StringUtils.isBlank(warnCookieGenerator.getCookiePath())) {
            logger.info("Setting path for cookies for warn cookie generator to: {} ", cookiePath);
            this.warnCookieGenerator.setCookiePath(cookiePath);
        } else {
            logger.debug("Warning cookie path is set to {} and path {}", warnCookieGenerator.getCookieDomain(),
                    warnCookieGenerator.getCookiePath());
        }
        if (StringUtils.isBlank(ticketGrantingTicketCookieGenerator.getCookiePath())) {
            logger.info("Setting path for cookies for TGC cookie generator to: {} ", cookiePath);
            this.ticketGrantingTicketCookieGenerator.setCookiePath(cookiePath);
        } else {
            logger.debug("TGC cookie path is set to {} and path {}", ticketGrantingTicketCookieGenerator.getCookieDomain(),
                    ticketGrantingTicketCookieGenerator.getCookiePath());
        }
//將TGT放在FlowScope作用域中 
        WebUtils.putTicketGrantingTicketInScopes(context,
                this.ticketGrantingTicketCookieGenerator.retrieveCookieValue(request));
//將warnCookieValue放在FlowScope作用域中
        WebUtils.putWarningCookie(context,
                Boolean.valueOf(this.warnCookieGenerator.retrieveCookieValue(request)));
//獲取service參數(shù)
        final Service service = WebUtils.getService(this.argumentExtractors, context);


        if (service != null) {
            logger.debug("Placing service in context scope: [{}]", service.getId());

            final RegisteredService registeredService = this.servicesManager.findServiceBy(service);
            if (registeredService != null && registeredService.getAccessStrategy().isServiceAccessAllowed()) {
                logger.debug("Placing registered service [{}] with id [{}] in context scope",
                        registeredService.getServiceId(),
                        registeredService.getId());
                WebUtils.putRegisteredService(context, registeredService);

                final RegisteredServiceAccessStrategy accessStrategy = registeredService.getAccessStrategy();
                if (accessStrategy.getUnauthorizedRedirectUrl() != null) {
                    logger.debug("Placing registered service's unauthorized redirect url [{}] with id [{}]in context scope",
                            accessStrategy.getUnauthorizedRedirectUrl(),
                            registeredService.getServiceId());
                    WebUtils.putUnauthorizedRedirectUrl(context, accessStrategy.getUnauthorizedRedirectUrl());
                }
            }
        } else if (!this.enableFlowOnAbsentServiceRequest) {
            logger.warn("No service authentication request is available at [{}]. CAS is configured to disable the flow.",
                    WebUtils.getHttpServletRequest(context).getRequestURL());
            throw new NoSuchFlowExecutionException(context.getFlowExecutionContext().getKey(),
                    new UnauthorizedServiceException("screen.service.required.message", "Service is required"));
        }
//將service放在FlowScope作用域中 
        WebUtils.putService(context, service);
        return result("success");
    }

InitialFlowSetupAction的doExecute要做的就是把ticketGrantingTicketId,warnCookieValue和service放到FlowScope的作用域中,以便在登錄流程中的state中進(jìn)行判斷。初始化完成后,登錄流程流轉(zhuǎn)到第一個(gè)state(ticketGrantingTicketExistsCheck)。

<action-state id="ticketGrantingTicketCheck">
        <evaluate expression="ticketGrantingTicketCheckAction"/>
        <transition on="notExists" to="gatewayRequestCheck"/>
        <transition on="invalid" to="terminateSession"/>
        <transition on="valid" to="hasServiceCheck"/>
    </action-state>

ticketGrantingTicketCheckAction的doExecute方法判斷request的Cookie中是否攜帶有效的TGT,第一次訪問(wèn)時(shí)沒(méi)有攜帶TGT,流程跳轉(zhuǎn)到gatewayRequestCheck。

<decision-state id="gatewayRequestCheck">
        <if test="requestParameters.gateway != '' and requestParameters.gateway != null and flowScope.service != null"
            then="gatewayServicesManagementCheck" else="serviceAuthorizationCheck"/>
    </decision-state>

因?yàn)槌跏蓟瘯r(shí),盡管把service保存在了FlowScope作用域中,但request中的參數(shù)gateway不存在,登錄流程流轉(zhuǎn)到第三個(gè)state(serviceAuthorizationCheck)。

 <action-state id="serviceAuthorizationCheck">
        <evaluate expression="serviceAuthorizationCheck"/>
        <transition to="initializeLogin"/>
    </action-state>

ServiceAuthorizationCheck的doExecute方法,要做的就是判斷FlowScope作用域中是否存在service,如果service存在,查找service的注冊(cè)信息。登錄流程流轉(zhuǎn)到第四個(gè)state(generateLoginTicket)。

  <action-state id="initializeLogin">
        <evaluate expression="'success'"/>
        <transition on="success" to="viewLoginForm"/>
    </action-state>

initializeLogin不做判斷,存在只是為了兼容舊cas版本。直接跳轉(zhuǎn)到viewLoginForm。

<view-state id="viewLoginForm" view="casLoginView" model="credential">
        <binder>
            <binding property="username" required="true"/>
            <binding property="password" required="true"/>
        </binder>
        <on-entry>
            <set name="viewScope.commandName" value="'credential'"/>
        </on-entry>
        <transition on="submit" bind="true" validate="true" to="realSubmit"/>
    </view-state>

此時(shí)流轉(zhuǎn)到CAS單點(diǎn)登錄服務(wù)器端的登錄頁(yè)面casLoginView.jsp。

<action-state id="realSubmit">
        <evaluate
                expression="authenticationViaFormAction.submit(flowRequestContext, flowScope.credential, messageContext)"/>
        <transition on="warn" to="warn"/>
        <transition on="success" to="sendTicketGrantingTicket"/>
        <transition on="successWithWarnings" to="showMessages"/>
        <transition on="authenticationFailure" to="handleAuthenticationFailure"/>
        <transition on="error" to="initializeLogin"/>
    </action-state>

用戶在登錄頁(yè)面輸入賬號(hào)密碼提交后,流程走到realSumit。
authenticationViaFormAction類的submit()對(duì)用戶提交的認(rèn)證信息進(jìn)行驗(yàn)證。

public final Event submit(final RequestContext context, final Credential credential,
                              final MessageContext messageContext)  {
        //判斷是否是已登錄過(guò),請(qǐng)求ST的
        if (isRequestAskingForServiceTicket(context)) {
              //如果已登錄,則生成ST
return grantServiceTicket(context, credential);
        }
       //未登陸過(guò),生成TGT
        return createTicketGrantingTicket(context, credential, messageContext);
    }

驗(yàn)證成功則跳轉(zhuǎn)到sendTicketGrantingTicket。

<action-state id="sendTicketGrantingTicket">
        <evaluate expression="sendTicketGrantingTicketAction"/>
        <transition to="serviceCheck"/>
    </action-state>

接著跳轉(zhuǎn)到serviceCheck

<decision-state id="serviceCheck">
        <if test="flowScope.service != null" then="generateServiceTicket" else="viewGenericLoginSuccess"/>
    </decision-state>

判斷是否是由應(yīng)用頁(yè)面跳轉(zhuǎn)到登錄頁(yè)面登陸的,如果是,則跳轉(zhuǎn)到generateServiceTicket,不是則跳轉(zhuǎn)到viewGenericLoginSuccess。
此處我們跳轉(zhuǎn)到generateServiceTicket

 <action-state id="generateServiceTicket">
        <evaluate expression="generateServiceTicketAction"/>
        <transition on="success" to="warn"/>
        <transition on="unregisteredService" to="viewGenericLoginSuccess"/>
        <transition on="authenticationFailure" to="handleAuthenticationFailure"/>
        <transition on="error" to="initializeLogin"/>
        <transition on="gateway" to="gatewayServicesManagementCheck"/>
    </action-state>

generateServiceTicketAction類的doExecute方法生成ST,并跳轉(zhuǎn)到warn

 <decision-state id="warn">
        <if test="flowScope.warnCookieValue" then="showWarningView" else="redirect"/>
    </decision-state>

跳轉(zhuǎn)到redirect

 <action-state id="redirect">
        <evaluate expression="flowScope.service.getResponse(requestScope.serviceTicketId)"
                  result-type="org.jasig.cas.authentication.principal.Response" result="requestScope.response"/>
        <transition to="postRedirectDecision"/>
</action-state>

    <decision-state id="postRedirectDecision">
        <if test="requestScope.response.responseType.name() == 'POST'" then="postView" else="redirectView"/>
</decision-state>

    <end-state id="redirectView" view="externalRedirect:#{requestScope.response.url}"/>

最終返回給瀏覽器跳轉(zhuǎn)回Client1的響應(yīng)。

4.1.1.2 訪問(wèn)接入Cas系統(tǒng)的應(yīng)用系統(tǒng)Client2

訪問(wèn)Client1并登陸之后,訪問(wèn)Client2,與訪問(wèn)Client1一樣,先經(jīng)過(guò)initialFlowSetupAction。
隨后登錄流程流轉(zhuǎn)到第一個(gè)state(ticketGrantingTicketExistsCheck)。

<action-state id="ticketGrantingTicketCheck">
        <evaluate expression="ticketGrantingTicketCheckAction"/>
        <transition on="notExists" to="gatewayRequestCheck"/>
        <transition on="invalid" to="terminateSession"/>
        <transition on="valid" to="hasServiceCheck"/>
    </action-state>

因?yàn)橐呀?jīng)登陸過(guò),擁有請(qǐng)求的Cookie中存在有效的TGT,于是流程跳轉(zhuǎn)到hasServiceCheck。

 <decision-state id="hasServiceCheck">
        <if test="flowScope.service != null" then="renewRequestCheck" else="viewGenericLoginSuccess"/>
    </decision-state>

判斷是否是由應(yīng)用頁(yè)面跳轉(zhuǎn)到登錄頁(yè)面登陸的,如果是,則跳轉(zhuǎn)到generateServiceTicket,不是則跳轉(zhuǎn)到viewGenericLoginSuccess。
此處跳轉(zhuǎn)到renewRequestCheck。

 <decision-state id="renewRequestCheck">
        <if test="requestParameters.renew != '' and requestParameters.renew != null" then="serviceAuthorizationCheck"
            else="generateServiceTicket"/>
    </decision-state>

request中不存在renew,登錄流程流轉(zhuǎn)到第四個(gè)state(generateServiceTicket)。

 <action-state id="generateServiceTicket">
        <evaluate expression="generateServiceTicketAction"/>
        <transition on="success" to="warn"/>
        <transition on="unregisteredService" to="viewGenericLoginSuccess"/>
        <transition on="authenticationFailure" to="handleAuthenticationFailure"/>
        <transition on="error" to="initializeLogin"/>
        <transition on="gateway" to="gatewayServicesManagementCheck"/>
    </action-state>

后續(xù)的流轉(zhuǎn)與應(yīng)用系統(tǒng)webapp1相同,請(qǐng)參考前面webapp1的流轉(zhuǎn)。

4.1.2 登出流程解析

登出的流程定義在logout-webflow.xml中。
首先訪問(wèn)登出接口/logout,流程跳轉(zhuǎn)到terminateSession

 <action-state id="terminateSession">
    <evaluate expression="terminateSessionAction.terminate(flowRequestContext)" />
    <transition to="doLogout" />
  </action-state>

登出的方法主要調(diào)用路徑如下:

TerminateSessionAction.terminate() 
--> CentralAuthenticationServiceImpl.destroyTicketGrantingTicket()
銷毀TGT的方法
--> LogoutManagerImpl.performLogout() 
執(zhí)行登出的方法,在該方法中向每個(gè)訪問(wèn)過(guò)的應(yīng)用系統(tǒng)發(fā)送登出請(qǐng)求, 應(yīng)用系統(tǒng)收到請(qǐng)求會(huì)銷毀與用戶的session
--> handleLogoutForSloService()
向應(yīng)用系統(tǒng)發(fā)送登出請(qǐng)求的方法
--> performBackChannelLogout()   發(fā)送登出請(qǐng)求

terminateSessionAction.terminate()執(zhí)行完畢之后,流程跳轉(zhuǎn)到doLogout

 <action-state id="doLogout">
    <evaluate expression="logoutAction" />
    <transition on="finish" to="finishLogout" />
    <transition on="front" to="frontLogout" />
  </action-state>

 <decision-state id="finishLogout">
    <if test="flowScope.logoutRedirectUrl != null" then="redirectView" else="logoutView" />
  </decision-state>

  <end-state id="logoutView" view="externalRedirect:casLoginView" />

最終跳轉(zhuǎn)到登錄頁(yè)面。

4.2 Client端源碼解析

Cas client應(yīng)用系統(tǒng)端通過(guò)幾個(gè)Filter來(lái)實(shí)現(xiàn)登陸跳轉(zhuǎn)和登出等功能。
下面以在web.xml中配置的幾個(gè)Filter順序來(lái)進(jìn)行分析 。

4.2.1 SingleSignOutFilter

org.jasig.cas.client.session.SingleSignOutFilter是處理登出請(qǐng)求的Filter。該Filter判斷是否是Cas Server端發(fā)過(guò)來(lái)的登出請(qǐng)求,如果是登出請(qǐng)求,則根據(jù)請(qǐng)求中的logoutMessage清除對(duì)應(yīng)的Session。
登出請(qǐng)求的主要調(diào)用路徑如下:

SingleSignOutFilter.doFilter()
--> SingleSignOutHandler.process()
--> destroySession(request)
--> session.invalidate();
4.2.2 AuthenticationFilter

org.jasig.cas.client.authentication.AuthenticationFilter是驗(yàn)證請(qǐng)求是否登陸過(guò)的Filter。

public final void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest)servletRequest;
        HttpServletResponse response = (HttpServletResponse)servletResponse;
        // 判斷該請(qǐng)求是否不需要驗(yàn)證,如果不需要,則跳轉(zhuǎn)到下一個(gè)Filter
if(this.isRequestUrlExcluded(request)) {
            this.logger.debug("Request is ignored.");
            filterChain.doFilter(request, response);
        } else {
            HttpSession session = request.getSession(false);
           //從session中獲取名為"_const_cas_assertion_"的Assertion 
 Assertion assertion = session != null?(Assertion)session.getAttribute("_const_cas_assertion_"):null;
           //如果存在,則說(shuō)明已經(jīng)登錄,本過(guò)濾器處理完成,處理下個(gè)過(guò)濾器 
          if(assertion != null) {
                filterChain.doFilter(request, response);
            } else {
//生成serviceUrl  
                String serviceUrl = this.constructServiceUrl(request, response);
//從request中獲取ST 
                String ticket = this.retrieveTicketFromRequest(request);
                boolean wasGatewayed = this.gateway && this.gatewayStorage.hasGatewayedAlready(request, serviceUrl);
                //如果ticket不為空,本過(guò)濾器處理完成,處理下個(gè)過(guò)濾器 
if(!CommonUtils.isNotBlank(ticket) && !wasGatewayed) {
                    this.logger.debug("no ticket and no assertion found");
                    String modifiedServiceUrl;
                    if(this.gateway) {
                        this.logger.debug("setting gateway attribute in session");
                        modifiedServiceUrl = this.gatewayStorage.storeGatewayInformation(request, serviceUrl);
                    } else {
                        modifiedServiceUrl = serviceUrl;
                    }

                    this.logger.debug("Constructed service url: {}", modifiedServiceUrl);
                  //生成重定向URL 
                    String urlToRedirectTo = CommonUtils.constructRedirectUrl(this.casServerLoginUrl, this.getProtocol().getServiceParameterName(), modifiedServiceUrl, this.renew, this.gateway);
                    this.logger.debug("redirecting to \"{}\"", urlToRedirectTo);
                    String reqType = request.getHeader("X-Requested-With");
                    //如果是異步請(qǐng)求,則返回410狀態(tài)碼給前端
                    if("XMLHttpRequest".equalsIgnoreCase(reqType)) {
                        String json = "{\"flag\":0,\"error\":401,\"data\":{}}";
                        response.getWriter().write(json);
                    } else {
                    //跳轉(zhuǎn)到CAS服務(wù)器的登錄頁(yè)面 
                        this.authenticationRedirectStrategy.redirect(request, response, urlToRedirectTo);
                    }

                } else {
                    filterChain.doFilter(request, response);
                }
            }
        }
    }

當(dāng)我們從瀏覽器訪問(wèn)配置了單點(diǎn)登錄的應(yīng)用系統(tǒng)時(shí)(http://www.client1.com/index),由于集成了CAS單點(diǎn)登錄客戶端,此時(shí)進(jìn)入到第一個(gè)過(guò)濾器AuthenticationFilter(不考慮其他非單點(diǎn)登錄的過(guò)濾器),執(zhí)行以下操作:
1 從session中獲取名為“const_cas_assertion”的assertion對(duì)象,判斷assertion是否存在,如果存在,說(shuō)明已經(jīng)登錄,執(zhí)行下一個(gè)過(guò)濾器。如果不存在,執(zhí)行第2步。
2 生成serviceUrl(http://www.client1.com/index),從request中獲取票據(jù)參數(shù)ticket,判斷ticket是否為空,如果不為空?qǐng)?zhí)行下一個(gè)過(guò)濾器。如果為空,執(zhí)行第3步。
3 生成重定向URL,如:
http://www.casserver.com/login?service=http://www.client1.com/index
4 跳轉(zhuǎn)到單點(diǎn)登錄服務(wù)器,顯示登錄頁(yè)面,此時(shí)第一個(gè)過(guò)濾器執(zhí)行完成。

4.2.3 ticketValidationFilter

org.jasig.cas.client.validation.Cas20ProxyReceivingTicketValidationFilter為驗(yàn)證Service Ticket的Filter。
Cas20ProxyReceivingTicketValidationFilter父類AbstractTicketValidationFilter中的doFilter方法:

public final void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        if(this.preFilter(servletRequest, servletResponse, filterChain)) {
            HttpServletRequest request = (HttpServletRequest)servletRequest;
            HttpServletResponse response = (HttpServletResponse)servletResponse;
            //從request中獲取參數(shù) 
            String ticket = this.retrieveTicketFromRequest(request);
            //ticket不為空,驗(yàn)證ticket,否則本過(guò)濾器處理完成,處理下個(gè)過(guò)濾器
            if(CommonUtils.isNotBlank(ticket)) {
                this.logger.debug("Attempting to validate ticket: {}", ticket);

                try {
//驗(yàn)證ticket并產(chǎn)生Assertion對(duì)象,錯(cuò)誤拋出TicketValidationException異常 
  Assertion assertion = this.ticketValidator.validate(ticket, this.constructServiceUrl(request, response));
             this.logger.debug("Successfully authenticated user: {}", assertion.getPrincipal().getName());
                   //給request設(shè)置assertion
                   request.setAttribute("_const_cas_assertion_", assertion);
                   //給session設(shè)置assertion  
                   if(this.useSession) {
                        request.getSession().setAttribute("_const_cas_assertion_", assertion);
                    }

                    this.onSuccessfulValidation(request, response, assertion);
                    if(this.redirectAfterValidation) {
                        this.logger.debug("Redirecting after successful ticket validation.");
                        response.sendRedirect(this.constructServiceUrl(request, response));
                        return;
                    }
                } catch (TicketValidationException var8) {
                    this.logger.debug(var8.getMessage(), var8);
                    this.onFailedValidation(request, response);
                    if(this.exceptionOnValidationFailure) {
                        throw new ServletException(var8);
                    }

                    response.sendError(403, var8.getMessage());
                    return;
                }
            }

            filterChain.doFilter(request, response);
        }
    }

假設(shè)當(dāng)執(zhí)行完第一個(gè)過(guò)濾器后,跳轉(zhuǎn)到CAS服務(wù)器端的登錄頁(yè)面,輸入用戶名和密碼,驗(yàn)證通過(guò)后。CAS服務(wù)器端會(huì)生成ticket,并將ticket作為重新跳轉(zhuǎn)到應(yīng)用系統(tǒng)的參數(shù)(http://www.client1.com/index?ticket=ST-1-4hH2s5tzsMGCcToDvGCb-cas01.example.org)。此時(shí)又進(jìn)入第一個(gè)過(guò)濾器AuthenticationFilter,由于存在ticket參數(shù),進(jìn)入到第二個(gè)過(guò)濾器TicketValidationFilter,執(zhí)行以下操作:
1 從request獲取ticket參數(shù),如果ticket為空,繼續(xù)處理下一個(gè)過(guò)濾器。如果參數(shù)不為空,驗(yàn)證ticket參數(shù)的合法性。
2 驗(yàn)證ticket,TicketValidationFilter的validate方法通過(guò)httpClient訪問(wèn)CAS服務(wù)器端(http://www.casserver.com/serviceValidate?ticket=ST-1-4hH2s5tzsMGCcToDvGCb-cas01.example.org&service=http://www.client1.com/index)驗(yàn)證ticket是否正確,并返回assertion對(duì)象。如果驗(yàn)證失敗,拋出異常,跳轉(zhuǎn)到錯(cuò)誤頁(yè)面。如果驗(yàn)證成功,session會(huì)以"const_cas_assertion"的名稱保存assertion對(duì)象,繼續(xù)處理下一個(gè)過(guò)濾器。

4.2.4 HttpServletRequestWrapperFilter

org.jasig.cas.client.util.HttpServletRequestWrapperFilter對(duì)HttpServletRequest對(duì)象再包裝一次,讓其支持getUserPrincipal,getRemoteUser方法來(lái)取得登錄的用戶信息。

public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { 
 //從Session或者request中取得AttributePrincipal,其實(shí)Assertion的一個(gè)principal屬性 
AttributePrincipal principal = this.retrievePrincipalFromSessionOrRequest(servletRequest);
//對(duì)request進(jìn)行包裝,并處理后面的過(guò)濾器,使其后面的過(guò)濾器或者servlet能夠在request.getRemoteUser()或者request.getUserPrincipal()取得用戶信息  
filterChain.doFilter(newHttpServletRequestWrapperFilter.CasHttpServletRequestWrapper((HttpServletRequest)servletRequest, principal), servletResponse); }

5 常見(jiàn)問(wèn)題

6 其他

6.1 Gradle相關(guān)

6.1.1 Gradle 打包實(shí)現(xiàn)生產(chǎn)環(huán)境與測(cè)試環(huán)境配置分離

在build.gradle中加入以下代碼

#默認(rèn)情況下為ent-dev
def env = System.getProperty("profile") ?: "ent-dev"
sourceSets {
    main {
        resources {
            srcDirs = ["src/main/resources", "src/main/$env"]
        }
    }
}

在/src/main目錄下建立各個(gè)環(huán)境目錄,如 ent-dev、ent-prod等。
對(duì)于cas系統(tǒng),配置參數(shù)都在cas.properties中,可以將cas.properties放入各個(gè)環(huán)境目錄中, 并修改讀取cas.properties路徑。
修改WEB-INF/spring-configuration目錄中的propertyFileConfigurer.xml

 <util:properties id="casProperties" location="${cas.properties.config.location:/WEB-INF/cas.properties}"/>

修改為

<util:properties id="casProperties" location="${cas.properties.config.location:classpath:/cas.properties}"/>

build生產(chǎn)環(huán)境時(shí)可使用命令:gradle build -D profile=ent-prod

6.2 調(diào)用263和LDAP驗(yàn)證用戶名密碼步驟

6.2.1 在項(xiàng)目中添加依賴

在項(xiàng)目build.gradle中加入以下內(nèi)容,如果是Maven項(xiàng)目,則在pom.xml文件中加入maven格式依賴。

shangdeCommonSdfVersion=0.1.0.5-ENT-SNAPSHOT
compile group: 'com.xxx.common', name: 'sdf-common-util', version: shangdeCommonSdfVersion
compile group: 'com.xxx.common', name: 'sdf-common-web', version: shangdeCommonSdfVersion
compile group: 'com.xxx.common', name: 'sdf-common-auth-web', version: shangdeCommonSdfVersion
compile group: 'com.xxx.common', name: 'sdf-common-sys', version: shangdeCommonSdfVersion
compile group: 'com.xxx.common', name: 'sdf-common-authentication-263', version: shangdeCommonSdfVersion
compile group: 'com.xxx.common', name: 'sdf-common-auth', version: shangdeCommonSdfVersion
6.2.2 在properties文件中添加以下內(nèi)容
263.domain=xyz.com
263.account=xyz.com
263.key=Zs54D6jo#
263.webServiceUrl=http://macom.263.net/axis/xmapi
ldap.url=ldap://172.16.117.215:389
6.2.3 調(diào)用驗(yàn)證方法
@Autowired
private SdfPasswordValidatorImpl sdfPasswordValidatorImpl;
// 返回值為true及驗(yàn)證成功
boolean isValidUser = sdfPasswordValidatorImpl.authenticate(username,password);
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容