package org.jeecg.modules.cas.util;
|
|
|
import java.io.StringReader;
|
import java.util.ArrayList;
|
import java.util.Collections;
|
import java.util.HashMap;
|
import java.util.LinkedList;
|
import java.util.List;
|
import java.util.Map;
|
|
import javax.xml.XMLConstants;
|
import javax.xml.parsers.DocumentBuilderFactory;
|
import javax.xml.parsers.ParserConfigurationException;
|
import javax.xml.parsers.SAXParser;
|
import javax.xml.parsers.SAXParserFactory;
|
import org.jeecg.common.constant.CommonConstant;
|
import org.w3c.dom.Document;
|
import org.xml.sax.Attributes;
|
import org.xml.sax.InputSource;
|
import org.xml.sax.SAXException;
|
import org.xml.sax.XMLReader;
|
import org.xml.sax.helpers.DefaultHandler;
|
|
import lombok.extern.slf4j.Slf4j;
|
|
/**
|
* 解析cas,ST验证后的xml
|
* @author: jeecg-boot
|
*/
|
@Slf4j
|
public final class XmlUtils {
|
|
/**
|
* attributes
|
*/
|
private static final String ATTRIBUTES = "attributes";
|
|
/**
|
* Creates a new namespace-aware DOM document object by parsing the given XML.
|
*
|
* @param xml XML content.
|
*
|
* @return DOM document.
|
*/
|
public static Document newDocument(final String xml) {
|
final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
|
final Map<String, Boolean> features = new HashMap(5);
|
features.put(XMLConstants.FEATURE_SECURE_PROCESSING, true);
|
features.put("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
|
for (final Map.Entry<String, Boolean> entry : features.entrySet()) {
|
try {
|
factory.setFeature(entry.getKey(), entry.getValue());
|
} catch (ParserConfigurationException e) {
|
log.warn("Failed setting XML feature {}: {}", entry.getKey(), e);
|
}
|
}
|
factory.setNamespaceAware(true);
|
try {
|
return factory.newDocumentBuilder().parse(new InputSource(new StringReader(xml)));
|
} catch (Exception e) {
|
throw new RuntimeException("XML parsing error: " + e);
|
}
|
}
|
|
/**
|
* Get an instance of an XML reader from the XMLReaderFactory.
|
*
|
* @return the XMLReader.
|
*/
|
public static XMLReader getXmlReader() {
|
try {
|
final XMLReader reader = SAXParserFactory.newInstance().newSAXParser().getXMLReader();
|
reader.setFeature("http://xml.org/sax/features/namespaces", true);
|
reader.setFeature("http://xml.org/sax/features/namespace-prefixes", false);
|
reader.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
|
return reader;
|
} catch (final Exception e) {
|
throw new RuntimeException("Unable to create XMLReader", e);
|
}
|
}
|
|
|
/**
|
* Retrieve the text for a group of elements. Each text element is an entry
|
* in a list.
|
* <p>This method is currently optimized for the use case of two elements in a list.
|
*
|
* @param xmlAsString the xml response
|
* @param element the element to look for
|
* @return the list of text from the elements.
|
*/
|
public static List<String> getTextForElements(final String xmlAsString, final String element) {
|
final List<String> elements = new ArrayList<String>(2);
|
final XMLReader reader = getXmlReader();
|
|
final DefaultHandler handler = new DefaultHandler() {
|
|
private boolean foundElement = false;
|
|
private StringBuilder buffer = new StringBuilder();
|
|
@Override
|
public void startElement(final String uri, final String localName, final String qName,
|
final Attributes attributes) throws SAXException {
|
if (localName.equals(element)) {
|
this.foundElement = true;
|
}
|
}
|
|
@Override
|
public void endElement(final String uri, final String localName, final String qName) throws SAXException {
|
if (localName.equals(element)) {
|
this.foundElement = false;
|
elements.add(this.buffer.toString());
|
this.buffer = new StringBuilder();
|
}
|
}
|
|
@Override
|
public void characters(char[] ch, int start, int length) throws SAXException {
|
if (this.foundElement) {
|
this.buffer.append(ch, start, length);
|
}
|
}
|
};
|
|
reader.setContentHandler(handler);
|
reader.setErrorHandler(handler);
|
|
try {
|
reader.parse(new InputSource(new StringReader(xmlAsString)));
|
} catch (final Exception e) {
|
log.error(e.getMessage(), e);
|
return null;
|
}
|
|
return elements;
|
}
|
|
/**
|
* Retrieve the text for a specific element (when we know there is only
|
* one).
|
*
|
* @param xmlAsString the xml response
|
* @param element the element to look for
|
* @return the text value of the element.
|
*/
|
public static String getTextForElement(final String xmlAsString, final String element) {
|
final XMLReader reader = getXmlReader();
|
final StringBuilder builder = new StringBuilder();
|
|
final DefaultHandler handler = new DefaultHandler() {
|
|
private boolean foundElement = false;
|
|
@Override
|
public void startElement(final String uri, final String localName, final String qName,
|
final Attributes attributes) throws SAXException {
|
if (localName.equals(element)) {
|
this.foundElement = true;
|
}
|
}
|
|
@Override
|
public void endElement(final String uri, final String localName, final String qName) throws SAXException {
|
if (localName.equals(element)) {
|
this.foundElement = false;
|
}
|
}
|
|
@Override
|
public void characters(char[] ch, int start, int length) throws SAXException {
|
if (this.foundElement) {
|
builder.append(ch, start, length);
|
}
|
}
|
};
|
|
reader.setContentHandler(handler);
|
reader.setErrorHandler(handler);
|
|
try {
|
reader.parse(new InputSource(new StringReader(xmlAsString)));
|
} catch (final Exception e) {
|
log.error(e.getMessage(), e);
|
return null;
|
}
|
|
return builder.toString();
|
}
|
|
|
public static Map<String, Object> extractCustomAttributes(final String xml) {
|
final SAXParserFactory spf = SAXParserFactory.newInstance();
|
spf.setNamespaceAware(true);
|
spf.setValidating(false);
|
try {
|
final SAXParser saxParser = spf.newSAXParser();
|
final XMLReader xmlReader = saxParser.getXMLReader();
|
final CustomAttributeHandler handler = new CustomAttributeHandler();
|
xmlReader.setContentHandler(handler);
|
xmlReader.parse(new InputSource(new StringReader(xml)));
|
return handler.getAttributes();
|
} catch (final Exception e) {
|
log.error(e.getMessage(), e);
|
return Collections.emptyMap();
|
}
|
}
|
|
private static class CustomAttributeHandler extends DefaultHandler {
|
|
private Map<String, Object> attributes;
|
|
private boolean foundAttributes;
|
|
private String currentAttribute;
|
|
private StringBuilder value;
|
|
@Override
|
public void startDocument() throws SAXException {
|
this.attributes = new HashMap(5);
|
}
|
|
@Override
|
public void startElement(final String nameSpaceUri, final String localName, final String qName,
|
final Attributes attributes) throws SAXException {
|
if (ATTRIBUTES.equals(localName)) {
|
this.foundAttributes = true;
|
} else if (this.foundAttributes) {
|
this.value = new StringBuilder();
|
this.currentAttribute = localName;
|
}
|
}
|
|
@Override
|
public void characters(final char[] chars, final int start, final int length) throws SAXException {
|
if (this.currentAttribute != null) {
|
value.append(chars, start, length);
|
}
|
}
|
|
@Override
|
public void endElement(final String nameSpaceUri, final String localName, final String qName)
|
throws SAXException {
|
if (ATTRIBUTES.equals(localName)) {
|
this.foundAttributes = false;
|
this.currentAttribute = null;
|
} else if (this.foundAttributes) {
|
final Object o = this.attributes.get(this.currentAttribute);
|
|
if (o == null) {
|
this.attributes.put(this.currentAttribute, this.value.toString());
|
} else {
|
final List<Object> items;
|
if (o instanceof List) {
|
items = (List<Object>) o;
|
} else {
|
items = new LinkedList<Object>();
|
items.add(o);
|
this.attributes.put(this.currentAttribute, items);
|
}
|
items.add(this.value.toString());
|
}
|
}
|
}
|
|
public Map<String, Object> getAttributes() {
|
return this.attributes;
|
}
|
}
|
|
|
public static void main(String[] args) {
|
String result = "<cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'>\r\n" +
|
" <cas:authenticationSuccess>\r\n" +
|
" <cas:user>admin</cas:user>\r\n" +
|
" <cas:attributes>\r\n" +
|
" <cas:credentialType>UsernamePasswordCredential</cas:credentialType>\r\n" +
|
" <cas:isFromNewLogin>true</cas:isFromNewLogin>\r\n" +
|
" <cas:authenticationDate>2019-08-01T19:33:21.527+08:00[Asia/Shanghai]</cas:authenticationDate>\r\n" +
|
" <cas:authenticationMethod>RestAuthenticationHandler</cas:authenticationMethod>\r\n" +
|
" <cas:successfulAuthenticationHandlers>RestAuthenticationHandler</cas:successfulAuthenticationHandlers>\r\n" +
|
" <cas:longTermAuthenticationRequestTokenUsed>false</cas:longTermAuthenticationRequestTokenUsed>\r\n" +
|
" </cas:attributes>\r\n" +
|
" </cas:authenticationSuccess>\r\n" +
|
"</cas:serviceResponse>";
|
|
String errorRes = "<cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'>\r\n" +
|
" <cas:authenticationFailure code=\"INVALID_TICKET\">未能够识别出目标 'ST-5-1g-9cNES6KXNRwq-GuRET103sm0-DESKTOP-VKLS8B3'票根</cas:authenticationFailure>\r\n" +
|
"</cas:serviceResponse>";
|
|
String error = XmlUtils.getTextForElement(errorRes, "authenticationFailure");
|
System.out.println("------"+error);
|
|
String error2 = XmlUtils.getTextForElement(result, "authenticationFailure");
|
System.out.println("------"+error2);
|
String principal = XmlUtils.getTextForElement(result, "user");
|
System.out.println("---principal---"+principal);
|
Map<String, Object> attributes = XmlUtils.extractCustomAttributes(result);
|
System.out.println("---attributes---"+attributes);
|
}
|
}
|