I tried to add SOAP header to my request via BindingProvider.getRequestContext().put(Header.HEADER_LIST, headers) but the SOAP Header is missing. My code is like the following:
Standard WebService class generated by CXF:
#WebService(targetNamespace = "...", name = "...")
#XmlSeeAlso({...ObjectFactory.class})
#SOAPBinding(parameterStyle = SOAPBinding.ParameterStyle.BARE)
public interface MyService {
...
#WebMethod(operationName = "...")
public Future<?> sendAsync(
#WebParam(partName = "parameters", name = "...", targetNamespace = "...")
MyRequestMessageType parameters,
#WebParam(name = "asyncHandler", targetNamespace = "")
AsyncHandler<MyResponseMessageType> asyncHandler
);
}
Standard WebServiceClient class generated by CXF
#WebServiceClient(name = "...", wsdlLocation = "...", targetNamespace = "...")
public class MyService_Service extends Service {
...
#WebEndpoint(name = "...")
public MyService getVendorManagementService() {
return super.getPort(MY_SERVICE, MyService.class);
}
}
Class which sends my request:
#Inject
private MyService_Service myService;
public void send() {
BindingProvider port = (BindingProvider) myService.getWebEndpointPort();
port.getRequestContext().put("thread.local.request.context", "true");
List<Header> headers = getHeaders(port.getRequestContext());
Header messageIDHeader = new Header(new QName("http://www.w3.org/2005/08/addressing", "MessageID", "wsa"), "some_id", new JAXBDataBinding(String.class));
headers.add(messageIDHeader);
port.getRequestContext().put(Header.HEADER_LIST, headers);
MyRequestMessageType message = messageCreator.createMyRequestMessage();
MyAsyncHandler asyncHandler = new MyAsyncHandler();
((MyService) port).sendAsync(message, asyncHandler);
}
private static List<Header> getHeaders(Map<String, Object> messageContext) {
if (messageContext == null) {
return null;
}
List<Header> headers = CastUtils.cast((List<?>) messageContext.get(Header.HEADER_LIST));
if (headers == null){
return new ArrayList<Header>();
}
return headers;
}
It generates correct request but SOAP Header is missing. The request contains only SOAP Body:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
... the message is OK
</soap:Body>
</soap:Envelope>
I have no idea what is wrong.
Thanks for any advice.
Now I use WebService (MyService) directly instead of getting it from WebServiceClient and it works. My send method looks like:
#Inject
private MyService port;
public void send() {
((BindingProvider) port).getRequestContext().put("thread.local.request.context", "true");
List<Header> headers = getHeaders(((BindingProvider) port).getRequestContext());
Header messageIDHeader = new Header(new QName("http://www.w3.org/2005/08/addressing", "MessageID", "wsa"), "some_id", new JAXBDataBinding(String.class));
headers.add(messageIDHeader);
((BindingProvider) port).getRequestContext().put(Header.HEADER_LIST, headers);
MyRequestMessageType message = messageCreator.createMyRequestMessage();
MyAsyncHandler asyncHandler = new MyAsyncHandler();
port.sendAsync(message, asyncHandler);
}
Another way to get the right ctx map is the following:
org.apache.cxf.endpoint.Client p =
org.apache.cxf.frontend.ClientProxy.getClient(myService);
Map<String, Object> ctx = p.getRequestContext();
ctx.put(Header.HEADER_LIST, headers);
Related
I'm implementing a ReactJs applications. I am using axios to invoke server side services built using Spring Boot. I need to send the header "Authorization: Bearer token-value". This is the client side code:
var options = {
withCredentials: true,
headers: {'Authorization': 'Bearer token-value'}
};
axios.post('http://localhost:9090/services/list', null, options)
.then((data) => {
console.log(data);
})
.catch((error) => {
console.error(error);
});
This is the Spring Boot controller:
#RestController
public class ServiceController {
private static final String AUTHORIZATION_HEADER_NAME = "Authorization";
private static final String BEARER = "Bearer ";
private static String getToken(HttpServletRequest request) {
String header = request.getHeader(AUTHORIZATION_HEADER_NAME);
if (header == null || header.trim().equals("")) {
return null;
}
header = header.trim();
if (!header.startsWith(BEARER)) {
return null;
}
return header.substring(BEARER.length()).trim();
}
#GetMapping
#RequestMapping(value = "/services/list", produces = "application/json", method = RequestMethod.POST)
public ResponseEntity<?> getTargets(HttpServletRequest request, HttpServletResponse response) {
String token = getToken(request);
if (token == null) {
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
}
DTOObject obj = goForTheBusinessObject(token);
return new ResponseEntity<>(obj, HttpStatus.OK);
}
}
This is the CORS configuration
#Configuration
public class RestConfig {
#Bean
public CorsFilter corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.addAllowedOrigin("*");
config.addAllowedHeader("*");
config.addAllowedMethod("POST");
config.addAllowedMethod("GET");
config.addAllowedMethod("DELETE");
config.addAllowedMethod("PUT");
source.registerCorsConfiguration("/**", config);
return new CorsFilter(source);
}
}
If I invoke the service using curl I got the expected response:
curl -X POST -H "Authorization: Bearer token-value" http://localhost:9090/services/list
If I invoke the service using post man, again I got the right answer.
But when I executed the ReactJS application, the server never receive the "Authorization" header.
Somebody help me please !!
You are facing CORS issues, Implement this class to resolve this-
#Component
public class CorsFilter implements WebFilter {
#Override
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
if (exchange != null) {
exchange.getResponse().getHeaders().add("Access-Control-Allow-Origin", "*");
exchange.getResponse().getHeaders().add("Access-Control-Allow-Methods", "GET, PUT, POST, DELETE, OPTIONS");
exchange.getResponse().getHeaders().add("Access-Control-Allow-Headers",
"DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range");
exchange.getResponse().getHeaders().add("Access-Control-Max-Age", "1728000");
if (exchange.getRequest().getMethod() == HttpMethod.OPTIONS) {
exchange.getResponse().getHeaders().add("Access-Control-Max-Age", "1728000");
exchange.getResponse().setStatusCode(HttpStatus.NO_CONTENT);
return Mono.empty();
} else {
exchange.getResponse().getHeaders().add("Access-Control-Expose-Headers", "DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range");
return chain.filter(exchange);
}
} else {
return chain.filter(exchange);
}
}
}
For more info on CORS visit this
Update: For scanning the component you can do following-
#ComponentScan(value = "com.pck", // cors filter package
useDefaultFilters = false)
public class MainClass {
public static void main(String[] args) {
ApplicationContext context = SpringApplication.
run(MainClass.class, args);
}
}
I have done an extensive search for the mentioned issue, but unable to find a workable solution.
Kindly have a look on some imp codes and suggest.
// My factory method that returns a promise
contactBackend : function(requestedMethod, requestedUrl,
requestedData) {
return $http({
method : requestedMethod,
url : backend + requestedUrl,
data : requestedData
});
}
//Actual Login method that calls the
loginC.validateLogin = function() {
welcomeMFactory.contactBackend("POST", "/rs/login",
loginC.user).then(
function(success) {
var msg = success.data.loginMsg;
if (msg == "login.valid") {
alert(JSON.stringify(success));
welcomeMFactory.moveToWidget("/home");
} else {
loginC.error = welcomeMFactory.printMsg(
true, msg);
}
},
function(error) {
loginC.error = welcomeMFactory.printMsg(true,
"Unable to reach backend for login");
});
}
// SpringController.xml
<mvc:cors>
<mvc:mapping path="/**" allowed-origins="http://localhost:8080"
allowed-headers="content-type,authentication" exposed-headers="content-type,authentication" />
</mvc:cors>
//Login Controller
#Autowired
private LoginRespI response;
#Autowired
private ProxyHandler proxyHandler;
#Autowired
private LoginServiceImpl loginServiceImpl;
#RequestMapping(method = RequestMethod.POST)
public LoginRespB authenticateUserLogin(#RequestBody LoginReqB request, HttpServletResponse resp) {
LoginDTO loginDTO = loginServiceImpl.validateLoginService(request.getUsername(), request.getPassword());
if (loginDTO != null) {
response.setLoginMsg("login.valid");
} else {
response.setLoginMsg("login.invalid");
}
Claims claims = Jwts.claims().setSubject("ABCDE");
claims.put("ID", "12345");
String toke = Jwts.builder().setClaims(claims).signWith(SignatureAlgorithm.HS512, "ABCDE").compact();
resp.setHeader("Authentication", "Bearer: " + toke);
return (LoginRespB) (proxyHandler.getTargetObject(response));
}
OPTIONS req/resp headers
Login req/resp headers
Add this method to your code ,it will allow cros domain request
package org.codingpedia.demo.rest.util;
import java.io.IOException;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerResponseContext;
import javax.ws.rs.container.ContainerResponseFilter;
import javax.ws.rs.core.MultivaluedMap;
public class CORSResponseFilter
implements ContainerResponseFilter {
public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext)
throws IOException {
MultivaluedMap<String, Object> headers = responseContext.getHeaders();
headers.add("Access-Control-Allow-Origin", "*");
//headers.add("Access-Control-Allow-Origin", "http://podcastpedia.org"); //allows CORS requests only coming from podcastpedia.org
headers.add("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT");
headers.add("Access-Control-Allow-Headers", "X-Requested-With, Content-Type, X-Codingpedia");
}
}
I am using AngularJS to send a POST request from my controller and I'm getting this error:
POST not supported
The JS function is the following:
addUserDetails: function(addUser) {
alert("M into add user function in service");
return restClientTemplate.execute({
method: 'POST',
url: 'json/user-add',
data: addUser
});
}
My Java Spring Controller is the following:
#Controller
public class AddUserController {
#Resource
private Settings settings;
#Resource
private RestOperations rest;
private static final String ORGANIZATION_URL_KEY = "configuration.organization.service.endpointUrl";
private static final String ORG_PRODUCT_LIST_URL_KEY = "configuration.org.product.list.service.endpointUrl";
#RequestMapping(value = "/json/user-add", method = RequestMethod.POST, produces = "application/json")
public ServiceResponse addOrganization(#RequestBody SaveOrganizationForm request) {
System.out.println("M into controllerrrr");
ObjectMapper objectMapper = new ObjectMapper();
ObjectNode requestBody = objectMapper.createObjectNode();
populateRequestObject(request, objectMapper, requestBody);
String url = MessageUtil.format(settings.getString(ORGANIZATION_URL_KEY) + "/s2");
ServiceResponse response = rest
.exchange(url, HttpMethod.POST, new HttpEntity<>(requestBody), ServiceResponse.class).getBody();
return response;
}
Have a problem with CORS filter, i think.
Because when i send request with Authorization header by Intellij Idea REST Tools, my filter catch a Authorization header.
But when i try to send request from client side from another server, filter does not see my header(return null).
I`m using spring boot, angularjs, salelizer and JWT for build token.
Params for building token on server side.
private static final JWSHeader JWT_HEADER = new JWSHeader(JWSAlgorithm.HS256);
private static final String TOKEN_SECRET = "Bearer";
public static final String AUTH_HEADER_KEY = "Authorization";
My Auth filter
public class AuthFilter implements Filter {
#Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
String authHeader = httpRequest.getHeader(AuthUtils.AUTH_HEADER_KEY);
if (StringUtils.isBlank(authHeader) || authHeader.split(" ").length != 2) {
httpResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED, AUTH_ERROR_MSG);
} else {
JWTClaimsSet claimSet = null;
try {
claimSet = (JWTClaimsSet) AuthUtils.decodeToken(authHeader);
} catch (ParseException e) {
httpResponse.sendError(HttpServletResponse.SC_BAD_REQUEST, JWT_ERROR_MSG);
return;
} catch (JOSEException e) {
httpResponse.sendError(HttpServletResponse.SC_BAD_REQUEST, JWT_INVALID_MSG);
return;
}
// ensure that the token is not expired
if (new DateTime(claimSet.getExpirationTime()).isBefore(DateTime.now())) {
httpResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED, EXPIRE_ERROR_MSG);
} else {
chain.doFilter(request, response);
}
}
}
#Override
public void destroy() { /* unused */ }
#Override
public void init(FilterConfig filterConfig) throws ServletException { /* unused */ }
}
My CORS filter in Web Mvc config file
#Bean
public CorsFilter corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.addAllowedOrigin("*");
config.addAllowedHeader("*");
config.addAllowedMethod("*");
config.addExposedHeader("Authorization");
config.addExposedHeader("Content-Type");
source.registerCorsConfiguration("/**", config);
return new CorsFilter(source);
}
My security configure
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.antMatchers(HttpMethod.OPTIONS,"**").permitAll().and().authorizeRequests()
.antMatchers( "/index","/api/**", "/auth/**", "/js/**", "/css/**", "/html/**")
.permitAll().anyRequest().authenticated();
My cliend side configs
function configHttp($httpProvider, $authProvider){
console.log("sdfd");
$httpProvider.defaults.headers.common["X-Requested-With"] = 'XMLHttpRequest';
$httpProvider.defaults.headers.common["Accept"] = "application/json";
$httpProvider.defaults.headers.common["Content-Type"] = "application/json";
var token = sessionStorage.getItem("satellizer_token");
if (token && $authProvider.httpInterceptor) {
token = $authProvider.authHeader === 'Authorization' ? 'Bearer ' + token : token;
$httpProvider.defaults.headers.common[$authProvider.authHeader] = token;
}
}
function configAuth($authProvider) {
$authProvider.httpInterceptor = function() { return true; };
$authProvider.baseUrl = 'http://localhost:8080';
$authProvider.loginUrl = '/auth/login';
$authProvider.signupUrl = '/auth/registration';
$authProvider.tokenName = 'token';
$authProvider.storageType = 'sessionStorage';
$authProvider.authToken = 'Bearer';
$authProvider.authHeader = 'Authorization';
}
There are a few options described here.
One option would be to annotate your controller method or class with #CrossOrigin.
If you want global config, you could add a new bean. I took this from the Spring doc listed above and modified it so that the mapping is /*. You can modify that path to be suitable for your application. According to the javadoc all origins will be allowed by default.
#Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurerAdapter() {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/*");
}
};
}
I've been dying for about 6 hours trying to figure out how to make a regular POST request in WP7 , I tried the answers of similar questions posted here and on many other places, I also tried many different APIs POST request, they all lead to one certain problem,
The remote server returned an error: NotFound.
it seems like everytime there's something missing.
So, if you please someone show us how to properly get a POST request right in this WP7
I use this to post to facebook without any problem:
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(requestUrl);
request.Method = "POST";
request.BeginGetResponse((e) =>
{
try
{
WebResponse response = request.EndGetResponse(e);
// Do Stuff
}
catch (WebException ex)
{
// Handle
}
catch (Exception ex)
{
// Handle
}
}, null);
I assume you would have tried this already so it may be something to do with the post data (which isn't in the above example as facebook uses the query string). Can you give us any more info?
EDIT: This is an (untested) example for writing post data:
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(requestUrl);
request.Method = "POST";
request.BeginGetRequestStream((e) =>
{
using (Stream stream = request.EndGetRequestStream(e))
{
// Write data to the request stream
}
request.BeginGetResponse((callback) =>
{
try
{
WebResponse response = request.EndGetResponse(callback);
// Do Stuff
}
catch (WebException ex)
{
// Handle
}
catch (Exception ex)
{
// Handle
}
}, null);
}, null);
I use the following class for making POST requests with WP7:
public class PostMultiPartFormData
{
private Dictionary<string, object> Parameters;
private Encoding ENCODING = Encoding.UTF8;
private string BOUNDARY = "-----------------------------wp7postrequest";
public event EventHandler PostComplete;
public void Post(string postbackURL,
Dictionary<string, object> parameters)
{
Parameters = parameters;
Uri url = null;
url = new Uri(postbackURL);
HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest;
request.Method = "POST";
request.ContentType = "multipart/form-data; boundary=" + BOUNDARY;
request.BeginGetRequestStream(new AsyncCallback(SendStatusUpdate), request);
}
private void SendStatusUpdate(IAsyncResult ar)
{
HttpWebRequest request = (HttpWebRequest)ar.AsyncState;
Stream stream = request.EndGetRequestStream(ar);
byte[] byteArray = GetMultipartFormData(Parameters, BOUNDARY);
stream.Write(byteArray, 0, byteArray.Length);
stream.Close();
stream.Dispose();
request.BeginGetResponse(new AsyncCallback(StatusUpdateCompleted), request);
}
private byte[] GetMultipartFormData(Dictionary<string, object> postParameters, string boundary)
{
Stream formDataStream = new System.IO.MemoryStream();
foreach (var param in postParameters)
{
if (param.Value is byte[])
{
byte[] fileData = param.Value as byte[];
string header = string.Format("--{0}\r\nContent-Disposition: form-data; name=\"{1}\"; filename=\"{2}.jpg\";\r\nContent-Type: application/octet-stream\r\n\r\n", boundary, param.Key, param.Key);
formDataStream.Write(ENCODING.GetBytes(header), 0, header.Length);
formDataStream.Write(fileData, 0, fileData.Length);
}
else
{
string postData = string.Format("--{0}\r\nContent-Disposition: form-data; name=\"{1}\"\r\n\r\n{2}\r\n", boundary, param.Key, param.Value);
byte[] b = ENCODING.GetBytes(postData);
foreach (var item in b)
{
formDataStream.WriteByte(item);
}
}
}
string footer = "\r\n--" + boundary + "--\r\n";
byte[] footerbytes = ENCODING.GetBytes(footer);
formDataStream.Write(footerbytes, 0, footerbytes.Length);
formDataStream.Position = 0;
byte[] formData = new byte[formDataStream.Length];
formDataStream.Read(formData, 0, formData.Length);
formDataStream.Flush();
formDataStream.Close();
return formData;
}
private void StatusUpdateCompleted(IAsyncResult ar)
{
if (PostComplete != null)
{
PostComplete(ar, null);
}
}
}
Example:
PostMultiPartFormData postRequest = new PostMultiPartFormData();
postRequest.PostComplete += new EventHandler( (sender, e) =>
{
IAsyncResult ar = ((IAsyncResult)sender);
using (WebResponse resp = ((HttpWebRequest)ar.AsyncState).EndGetResponse(ar))
{
using (StreamReader sr = new StreamReader(resp.GetResponseStream()))
{
string responseString = sr.ReadToEnd();
this.Dispatcher.BeginInvoke(() =>
{
textBlock.Text = responseString;
});
}
}
});
postRequest.Post("http://localhost:50624/SSLProxy.ashx",
new Dictionary<string, object>() { { "param1", "value1" } });
This should work...
If it doesn't let me know! :-)
For easier access to advanced http features check out these http classes:
http://mytoolkit.codeplex.com/wikipage?title=Http
It encapsulates GET, POST, FILES (using path or Stream objects) and GZIP (not directly supported by WP7) requests.
To add post data just call BeginGetRequestStream method (also, BeginGetResponse move to GetRequestStreamCallback)
request.BeginGetRequestStream(new AsyncCallback(GetRequestStreamCallback), request);
void GetRequestStreamCallback(IAsyncResult asynchronousResult)
{
HttpWebRequest webRequest = (HttpWebRequest)asynchronousResult.AsyncState;
// End the stream request operation
Stream postStream = webRequest.EndGetRequestStream(asynchronousResult);
// Create the post data
string postData = "post data";
byte[] byteArray = Encoding.Unicode.GetBytes(postData);
// Add the post data to the web request
postStream.Write(byteArray, 0, byteArray.Length);
postStream.Close();
// Start the web request
webRequest.BeginGetResponse(new AsyncCallback(GetResponseCallback), webRequest);
}
I recommend you to use the postclient. It is pretty simple. You just need to add reference to dll file into your project, and then write something like:
public void authorize(string login, string password)
{
Dictionary<string, object> parameters = new Dictionary<string, object>();
parameters.Add("command", "login");
parameters.Add("username", login);
parameters.Add("password", password);
PostClient proxy = new PostClient(parameters);
proxy.DownloadStringCompleted += (sender, e) =>
{
if (e.Error == null)
{
MessageBox.Show(e.Result);
}
};
proxy.DownloadStringAsync(new Uri("http://address.com/service", UriKind.Absolute));
}