一。設置移動客戶端驗證ST經過後,頁面不進行302重定向跳轉java
修改web.xmlweb
<!--***************************************************************** -->
<!-- 校驗ticket的過濾器 -->
<filter>
<filter-name>ticketValidationFilter</filter-name>
<filter-class>org.jasig.cas.client.validation.Cas20ProxyReceivingTicketValidationFilter
</filter-class>
<init-param>
<param-name>casServerUrlPrefix</param-name>
<!-- SSO統一登陸URL-->
<param-value>http://passport.hivescm.com/cas</param-value>
</init-param>
<init-param>
<param-name>serverName</param-name>
<!--本客戶端URL-->
<param-value>http://192.168.106.49:8080/order</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>false</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>ticketValidationFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>spring
二。處理移動端經過ST訪問另外一個系統比較service經過apache
1.移動端獲取TGT的類,查看源碼TicketsResource ,進行修改返回json數據json
package org.jasig.cas.support.rest; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.google.code.kaptcha.Constants; import com.hivecas.model.ConstantUtils; import com.hivecas.model.ResponseBean; import com.hivecas.model.UsernamePasswordStrongCredential; import org.apache.commons.lang3.StringUtils; import org.jasig.cas.CasProtocolConstants; import org.jasig.cas.CentralAuthenticationService; import org.jasig.cas.authentication.AuthenticationContext; import org.jasig.cas.authentication.AuthenticationContextBuilder; import org.jasig.cas.authentication.AuthenticationSystemSupport; import org.jasig.cas.authentication.AuthenticationException; import org.jasig.cas.authentication.AuthenticationTransaction; import org.jasig.cas.authentication.Credential; import org.jasig.cas.authentication.DefaultAuthenticationContextBuilder; import org.jasig.cas.authentication.DefaultAuthenticationSystemSupport; import org.jasig.cas.authentication.principal.Service; import org.jasig.cas.authentication.principal.ServiceFactory; import org.jasig.cas.ticket.InvalidTicketException; import org.jasig.cas.ticket.ServiceTicket; import org.jasig.cas.ticket.TicketGrantingTicket; import org.jasig.cas.ticket.registry.DefaultTicketRegistrySupport; import org.jasig.cas.ticket.registry.TicketRegistrySupport; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.util.MultiValueMap; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; import javax.servlet.http.HttpServletRequest; import javax.validation.constraints.NotNull; import java.net.URI; import java.util.Formatter; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; /** * {@link RestController} implementation of CAS' REST API. * * This class implements main CAS RESTful resource for vending/deleting TGTs and vending STs: * * <ul> * <li>{@code POST /v1/tickets}</li> * <li>{@code POST /v1/tickets/{TGT-id}}</li> * <li>{@code DELETE /v1/tickets/{TGT-id}}</li> * </ul> * * @author Dmitriy Kopylenko * @since 4.1.0 */ @RestController("ticketResourceRestController") public class TicketsResource { private static final Logger LOGGER = LoggerFactory.getLogger(TicketsResource.class); @Autowired @Qualifier("centralAuthenticationService") private CentralAuthenticationService centralAuthenticationService; @NotNull @Autowired(required=false) @Qualifier("defaultAuthenticationSystemSupport") private AuthenticationSystemSupport authenticationSystemSupport = new DefaultAuthenticationSystemSupport(); @Autowired(required = false) private final CredentialFactory credentialFactory = new DefaultCredentialFactory(); @Autowired @Qualifier("webApplicationServiceFactory") private ServiceFactory webApplicationServiceFactory; @Autowired @Qualifier("defaultTicketRegistrySupport") private TicketRegistrySupport ticketRegistrySupport = new DefaultTicketRegistrySupport(); private final ObjectMapper jacksonObjectMapper = new ObjectMapper(); /** * Create new ticket granting ticket. * * @param requestBody username and password application/x-www-form-urlencoded values * @param request raw HttpServletRequest used to call this method * @return ResponseEntity representing RESTful response * @throws JsonProcessingException in case of JSON parsing failure */ @RequestMapping(value = "/tickets", method = RequestMethod.POST, consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE) @ResponseBody public final ResponseBean createTicketGrantingTicket(@RequestBody final MultiValueMap<String, String> requestBody, final HttpServletRequest request) throws JsonProcessingException { ResponseBean responseBean=new ResponseBean(); try{ final String loginType = requestBody.getFirst("loginType"); final Credential credential = this.credentialFactory.fromRequestBody(requestBody); final AuthenticationContextBuilder builder = new DefaultAuthenticationContextBuilder( this.authenticationSystemSupport.getPrincipalElectionStrategy()); final AuthenticationTransaction transaction = AuthenticationTransaction.wrap(credential); this.authenticationSystemSupport.getAuthenticationTransactionManager().handle(transaction, builder); final AuthenticationContext authenticationContext = builder.build(); final TicketGrantingTicket tgtId = this.centralAuthenticationService.createMobileTicketGrantingTicket(authenticationContext,loginType); final URI ticketReference = new URI(request.getRequestURL().toString() + '/' + tgtId.getId()); final Map<String, String> dataMap = new HashMap<>(); dataMap.put("action", ticketReference.toString()); responseBean.setData(dataMap); responseBean.setStatus(ConstantUtils.response_Status.SUCCESS); return responseBean; } catch(final AuthenticationException e) { responseBean.setMsg("無權限"); responseBean.setStatus(ConstantUtils.response_Status.NO_AUTH); return responseBean; } catch (final BadRequestException e) { responseBean.setStatus(ConstantUtils.response_Status.FAIL); LOGGER.error(e.getMessage(), e); return responseBean; } catch (final Throwable e) { responseBean.setStatus(ConstantUtils.response_Status.FAIL); LOGGER.error(e.getMessage(), e); return responseBean; } } /** * Create new service ticket. * * @param requestBody service application/x-www-form-urlencoded value * @param tgtId ticket granting ticket id URI path param * @return {@link ResponseEntity} representing RESTful response */ @RequestMapping(value = "/tickets/{tgtId:.+}", method = RequestMethod.POST, consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE) @ResponseBody public final ResponseBean createServiceTicket(@RequestBody final MultiValueMap<String, String> requestBody, @PathVariable("tgtId") final String tgtId) { ResponseBean responseBean=new ResponseBean(); try { final String serviceId = requestBody.getFirst(CasProtocolConstants.PARAMETER_SERVICE); final AuthenticationContextBuilder builder = new DefaultAuthenticationContextBuilder( this.authenticationSystemSupport.getPrincipalElectionStrategy()); final Service service = this.webApplicationServiceFactory.createService(serviceId); final AuthenticationContext authenticationContext = builder.collect(this.ticketRegistrySupport.getAuthenticationFrom(tgtId)).build(service); final ServiceTicket serviceTicketId = this.centralAuthenticationService.grantServiceTicket(tgtId, service, authenticationContext); responseBean.setStatus(ConstantUtils.response_Status.SUCCESS); final Map<String, String> dataMap = new HashMap<>(); dataMap.put("serviceTicketId", serviceTicketId.getId()); responseBean.setData(dataMap); return responseBean; } catch (final InvalidTicketException e) { responseBean.setStatus(ConstantUtils.response_Status.NO_AUTH); responseBean.setMsg("TGT不存在"); return responseBean; } catch (final Exception e) { LOGGER.error(e.getMessage(), e); responseBean.setStatus(ConstantUtils.response_Status.FAIL); return responseBean; } } /** * Destroy ticket granting ticket. * * @param tgtId ticket granting ticket id URI path param * @return {@link ResponseEntity} representing RESTful response. Signals * {@link HttpStatus#OK} when successful. */ @RequestMapping(value = "/tickets/{tgtId:.+}", method = RequestMethod.DELETE) @ResponseBody public final ResponseBean deleteTicketGrantingTicket(@PathVariable("tgtId") final String tgtId) { this.centralAuthenticationService.destroyTicketGrantingTicket(tgtId); ResponseBean responseBean=new ResponseBean(); responseBean.setStatus(ConstantUtils.response_Status.SUCCESS); responseBean.setMsg("刪除成功"); return responseBean; } public void setAuthenticationSystemSupport(final AuthenticationSystemSupport authenticationSystemSupport) { this.authenticationSystemSupport = authenticationSystemSupport; } public void setWebApplicationServiceFactory(final ServiceFactory webApplicationServiceFactory) { this.webApplicationServiceFactory = webApplicationServiceFactory; } public void setTicketRegistrySupport(final TicketRegistrySupport ticketRegistrySupport) { this.ticketRegistrySupport = ticketRegistrySupport; } public void setCentralAuthenticationService(final CentralAuthenticationService centralAuthenticationService) { this.centralAuthenticationService = centralAuthenticationService; } public CentralAuthenticationService getCentralAuthenticationService() { return centralAuthenticationService; } public AuthenticationSystemSupport getAuthenticationSystemSupport() { return authenticationSystemSupport; } public CredentialFactory getCredentialFactory() { return credentialFactory; } public ServiceFactory getWebApplicationServiceFactory() { return webApplicationServiceFactory; } public TicketRegistrySupport getTicketRegistrySupport() { return ticketRegistrySupport; } /** * Default implementation of CredentialFactory. */ private static class DefaultCredentialFactory implements CredentialFactory { @Override public Credential fromRequestBody(@NotNull final MultiValueMap<String, String> requestBody) { final String username = requestBody.getFirst("username"); final String password = requestBody.getFirst("password"); final String loginType = requestBody.getFirst("loginType"); if(username == null || password == null||loginType==null) { throw new BadRequestException("Invalid payload. 'username' and 'password' form fields are required."); } if(!StringUtils.equals(loginType, ConstantUtils.loginType.MOBILE)){ throw new BadRequestException("Invalid payload. 'loginType' is wrong."); } return new UsernamePasswordStrongCredential(username, password,loginType); } } /** * Exception to indicate bad payload. */ private static class BadRequestException extends IllegalArgumentException { private static final long serialVersionUID = 6852720596988243487L; /** * Ctor. * @param msg error message */ BadRequestException(final String msg) { super(msg); } } }
2.返回responsebeanapp
package com.hivecas.model; import java.util.Map; public class ResponseBean { //返回狀態 1 成功 2 失敗 public String status; //返回數據 public Map data; //返回信息 public String msg; public String getStatus() { return status; } public void setStatus(String status) { this.status = status; } public Map getData() { return data; } public void setData(Map data) { this.data = data; } public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } }
3.在源碼CentralAuthenticationServiceImpl添加createMobileTicketGrantingTicket方法,將移動登陸的類型loginType 設置到TGT中ide
@Audit( action="TICKET_GRANTING_TICKET", actionResolverName="CREATE_TICKET_GRANTING_TICKET_RESOLVER", resourceResolverName="CREATE_TICKET_GRANTING_TICKET_RESOURCE_RESOLVER") @Timed(name = "CREATE_TICKET_GRANTING_TICKET_TIMER") @Metered(name = "CREATE_TICKET_GRANTING_TICKET_METER") @Counted(name="CREATE_TICKET_GRANTING_TICKET_COUNTER", monotonic=true) public TicketGrantingTicket createMobileTicketGrantingTicket(final AuthenticationContext context,final String loginType) throws AuthenticationException, AbstractTicketException { final Authentication authentication = context.getAuthentication(); final TicketGrantingTicketFactory factory = this.ticketFactory.get(TicketGrantingTicket.class); final TicketGrantingTicket ticketGrantingTicket = factory.create(authentication,loginType); this.ticketRegistry.addTicket(ticketGrantingTicket); doPublishEvent(new CasTicketGrantingTicketCreatedEvent(this, ticketGrantingTicket)); return ticketGrantingTicket; }
4.源碼TicketGrantingTicket添加獲取getLoginType方法ui
public interface TicketGrantingTicket extends Ticket { /** The prefix to use when generating an id for a Ticket Granting Ticket. */ String PREFIX = "TGT"; String getLoginType();
5.這就能夠在客戶端請求ST票據驗證時,不進行service的url比較驗證,直接經過。位置在源碼CentralAuthenticationServiceImpl類中this
@Audit( action="SERVICE_TICKET_VALIDATE", actionResolverName="VALIDATE_SERVICE_TICKET_RESOLVER", resourceResolverName="VALIDATE_SERVICE_TICKET_RESOURCE_RESOLVER") @Timed(name="VALIDATE_SERVICE_TICKET_TIMER") @Metered(name="VALIDATE_SERVICE_TICKET_METER") @Counted(name="VALIDATE_SERVICE_TICKET_COUNTER", monotonic=true) @Override public Assertion validateServiceTicket(final String serviceTicketId, final Service service) throws AbstractTicketException { final RegisteredService registeredService = this.servicesManager.findServiceBy(service); verifyRegisteredServiceProperties(registeredService, service); final ServiceTicket serviceTicket = this.ticketRegistry.getTicket(serviceTicketId, ServiceTicket.class); if (serviceTicket == null) { logger.info("Service ticket [{}] does not exist.", serviceTicketId); throw new InvalidTicketException(serviceTicketId); } final TicketGrantingTicket root ; try { synchronized (serviceTicket) { if (serviceTicket.isExpired()) { logger.info("ServiceTicket [{}] has expired.", serviceTicketId); throw new InvalidTicketException(serviceTicketId); } root = serviceTicket.getGrantingTicket().getRoot(); if(root!=null){ String loginType=root.getLoginType(); if(StringUtils.isNotBlank(loginType)||StringUtils.equalsIgnoreCase(loginType, ConstantUtils.loginType.PC)){ if (!serviceTicket.isValidFor(service)) { logger.error("Service ticket [{}] with service [{}] does not match supplied service [{}]", serviceTicketId, serviceTicket.getService().getId(), service); throw new UnrecognizableServiceForServiceTicketValidationException(serviceTicket.getService()); } } } } // final TicketGrantingTicket root = serviceTicket.getGrantingTicket().getRoot(); final Authentication authentication = getAuthenticationSatisfiedByPolicy( root, new ServiceContext(serviceTicket.getService(), registeredService)); final Principal principal = authentication.getPrincipal(); final RegisteredServiceAttributeReleasePolicy attributePolicy = registeredService.getAttributeReleasePolicy(); logger.debug("Attribute policy [{}] is associated with service [{}]", attributePolicy, registeredService); @SuppressWarnings("unchecked") final Map<String, Object> attributesToRelease = attributePolicy != null ? attributePolicy.getAttributes(principal) : Collections.EMPTY_MAP; final String principalId = registeredService.getUsernameAttributeProvider().resolveUsername(principal, service); final Principal modifiedPrincipal = this.principalFactory.createPrincipal(principalId, attributesToRelease); final AuthenticationBuilder builder = DefaultAuthenticationBuilder.newInstance(authentication); builder.setPrincipal(modifiedPrincipal); final Assertion assertion = new ImmutableAssertion( builder.build(), serviceTicket.getGrantingTicket().getChainedAuthentications(), serviceTicket.getService(), serviceTicket.isFromNewLogin()); doPublishEvent(new CasServiceTicketValidatedEvent(this, serviceTicket, assertion)); return assertion; } finally { if (serviceTicket.isExpired()) { this.ticketRegistry.deleteTicket(serviceTicketId); } } } @Audit( action="TICKET_GRANTING_TICKET", actionResolverName="CREATE_TICKET_GRANTING_TICKET_RESOLVER", resourceResolverName="CREATE_TICKET_GRANTING_TICKET_RESOURCE_RESOLVER") @Timed(name = "CREATE_TICKET_GRANTING_TICKET_TIMER") @Metered(name = "CREATE_TICKET_GRANTING_TICKET_METER") @Counted(name="CREATE_TICKET_GRANTING_TICKET_COUNTER", monotonic=true) @Override public TicketGrantingTicket createTicketGrantingTicket(final AuthenticationContext context) throws AuthenticationException, AbstractTicketException { final Authentication authentication = context.getAuthentication(); final TicketGrantingTicketFactory factory = this.ticketFactory.get(TicketGrantingTicket.class); final TicketGrantingTicket ticketGrantingTicket = factory.create(authentication); this.ticketRegistry.addTicket(ticketGrantingTicket); doPublishEvent(new CasTicketGrantingTicketCreatedEvent(this, ticketGrantingTicket)); return ticketGrantingTicket; }