i want to generate unique md5 for every http request that will hit REST API.
So far i have just used String requestParameters but actual httpRequest will have many other things.
How can i achieve this ?
public final class MD5Generator {
public static String getMd5HashCode(String requestParameters) {
return DigestUtils.md5DigestAsHex(requestParameters.getBytes());
}
}
My Controller
#RequestMapping(value = { "/dummy" }, method = RequestMethod.GET)
public String processOperation(HttpServletRequest request) {
serviceLayer = new ServiceLayer(request);
return "wait operation is executing";
}
Service layer
private String httpRequestToString() {
String request = "";
Enumeration<String> requestParameters = httpRequest.getParameterNames();
while (requestParameters.hasMoreElements()) {
request += String.valueOf(requestParameters.nextElement());
}
if (!request.equalsIgnoreCase(""))
return request;
else {
throw new HTTPException(200);
}
}
private String getMD5hash() {
return MD5Generator.getMd5HashCode(httpRequestToString());
}
Do you see any issues with generating an UUID for every request and use that instead?
For example, you could generate the UUID and attach it to the request object if you need it during the request life-cycle:
String uuid = UUID.randomUUID().toString();
request.setAttribute("request-id", uuid);
You can combine request time (System.currentTimeMillis()) and remote address from HttpServletRequest. However, if you're expecting high loads, multiple requests may arrive from a particular client in the same millisecond. To overcome this situation, you may add a global atomic counter to your String combination.
Once you generate an MD5 key, you can set it in ThreadLocal to reach afterwards.
You can do this but in future maybe. I search and not found automated way to achieve this
#GetMapping("/user/{{md5(us)}}")
Related
I have an endpoint where it supposes to sends a string as a response. My question is do I need to use to response Entity to send string response or just return the string to the consumer?
#GetMapping(value = "/word")
public String getWord() {
String response = "webservice";
return response;
}
Second approach:
#GetMapping(value = "/word", produces ={MediaType.APPLICATION_JSON_VALUE})
public ResponseEntity<String> getWord() {
String response = "webservice";
return new ResponseEntity<>(response, HttpStatus.OK);
}
What is the correct approach to send just a string or use response entity?
What is the correct approach to send just a string or use response entity?
The Spring MVC documentation lists a number of types that can be returned from controller methods.
As I previously answered here and here, ResponseEntity<T> represents the entire HTTP response. Besides the body, its API allows you to set headers and a status code to the response.
Returning just a bean instance or a string is fine but doesn't give you much flexibility: In the future, if you need to add a header to the response or modify the status code, for example, you need to change the method return type.
At the moment my website is using Spring that handles the http(s) request to and from the front-end like this:
#RestController
public class ComputeController {
#RequestMapping(value = "/api/compute", method = RequestMethod.POST)
public String compute(#RequestBody CodeToken code, OAuth2Authentication OAuth2) {
Map<String, String> userInfo = UserInformation.getUserInfo(OAuth2);
String sourceCode = code.getSource();
String filename = code.getFilename();
String email = userInfo.get("email");
try {
DataStorage dateStorage = new DataStorage();
Compiler compiler = new Compiler(dateStorage);
return compiler.compile(filename, sourceCode, email);
} catch (Exception e) { // TODO Don't catch all exceptions
return e.getStackTrace().toString();
}
}
}
The problem is that I need my front-end (built in Angular) to be able to receive and send information asynchronous from the http(s) request sent from the front-end. Like an continuous I/O stream from the server mid request while the "compiler.compile(...)" is running.
I presume I need to use sockets for this but I'm looking for suggestion on a good way to implement them.
If I understand your intention correctly, you're trying to display some progress in your client while the code compiles. You have two options:
As you proposed, use WebSockets. Spring supports them well. You can see an example here: https://github.com/AlexeySoshin/SpringWebSockets/tree/master/src/main/java/com/alexeysoshin/chat
Instead of blocking your response,
Do compilation on a separate thread pool.
Assign each compilation UUID when you submit this task.
Return the client this task immediately.
Poll another endpoint with UUID
The authentication method has been integrated with every REST calls in the API. I have been trying to implement an authentication method via Spring AOP so that I can remove all the duplicate code from end-points and have one single advise to look for all public methods in Controllers.
Please check the below my code,
#Aspect
public class EndpointAccessAspect {
/**
* All the request mappings in controllers need to authenticate and validate end-point access
*/
#Before("execution(public * com.xxxx.webapi.controllers.MenuController.getCategory(HttpServletRequest)) && args(request)")
public void checkTokenAccess(HttpServletRequest request){
String re =(String) request.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE);
System.out.println(" %%%%%%%%%%%%%%%%%%% checkTokenAccess %%%%%%%%%%%%%%%" + re);
}
public void checkEndPointPermission(){
System.out.println(" $$$$$$$$$$$$$$$$$$ checkEndPointPermission &&&&&&&&&&&&&");
}
}
However, I saw Intelij gives error near getCategory(HttpServletRequest)) && args(request) saying can not resolve symbol HttpServletRequest. I need the request to distingues each REST end-points. There are more variables than HttpServletRequest variable in the method but only that variable is needed.
The code is compiling when I test the functionality I noticed it doesn't reach to the advise. Can anybody help me to fix this?
I found this from Spring documentation
Spring doc
any join point (method execution only in Spring AOP) which takes a
single parameter, and where the argument passed at runtime is
Serializable
Does this mean I can not use methods that have multiple parameters?
Controller end-point
#RequestMapping(value = "{menuId}/categories/{categoryId}", method = RequestMethod.GET)
#ApiResponses(value = {
#ApiResponse(code = 200, message = "Successful retrieval of a category requested", response = ProductGroupModel.class),
#ApiResponse(code = 500, message = "Internal server error") })
public ProductGroupModel getCategory(
#ApiParam(name = "menuId", value = "Numeric value for menuId", required = true) #PathVariable(value = "menuId") final String menuId,
#ApiParam(name = "categoryId", value = "Numeric value for categoryId", required = true) #PathVariable(value = "categoryId") final String categoryId,
final HttpServletRequest request) {
The following syntax, resolved the above issue. Basically, I had to modify the code to deal with multiple parameters in the advise.
#Before("execution(public * com.xxxx.webapi.controllers.MenuController.getCategory( HttpServletRequest,..)) && args(request, ..)")
public void checkTokenAccess(HttpServletRequest request){
String re =(String) request.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE);
System.out.println(" %%%%%%%%%%%%%%%%%%% checkTokenAccess %%%%%%%%%%%%%%%" + re);
}
I have a working Jersey/Atmosphere/Guice application which has two Atmosphere Resources. The first is pretty much a clone of the example chat application:
#Path("/chat")
#AtmosphereService(broadcaster = JerseyBroadcaster.class, path = "/chat")
public class ChatResource {
#Suspend(contentType = "application/json")
#GET
public String suspend() {
return "";
}
#Broadcast(writeEntity = false)
#POST
#Produces("application/json")
public Response broadcast(Message message) {
return new Response(message.author, message.message);
}
}
The second is a test notification resource which will be sent server-side events:
#Path("/notifications")
#AtmosphereService(broadcaster = JerseyBroadcaster.class, path = "/notifications")
public class NotificationsResource {
#Suspend(contentType = "application/json")
#GET
public String suspend() {
return "";
}
}
Everything is wired up correctly and works fine. However in order for me to send a server side event I issue:
MetaBroadcaster.getDefault().broadcastTo("/*", new Response(...));
Clearly, this will send the broadcast message to both resources. What I want to do is send the server side events only to the notifications resource:
MetaBroadcaster.getDefault().broadcastTo("/notifications", new NotificationResponse(...));
However, that doesn't work. I always receive the following error:
org.atmosphere.cpr.MetaBroadcaster - No Broadcaster matches /notifications.
That's because there is only one broadcaster registered; the JerseyBroadcaster on /*.
The question is: how do I make it so that these two resources have different broadcasters with different IDs/Names?
In the resource, suspend using the channel you want (the 'true' parameter to lookup() forces the channel to be created if it doesn't exist):
#Suspend( contentType = MediaType.APPLICATION_JSON, period = MAX_SUSPEND_MSEC )
#GET
public Broadcastable suspend( #Context final BroadcasterFactory factory )
{
return new Broadcastable( factory.lookup( MY_CHANNEL, true ) );
}
In the other code, which can be pretty much anywhere, broadcast to that channel:
Broadcaster broadcaster = BroadcasterFactory.getDefault().lookup( MY_CHANNEL );
if( broadcaster != null ) {
broadcaster.broadcast( message );
}
If you're going to be broadcasting from a resource method, you can annotate it instead (as shown in ChatResource's broadcast() method).
Just inject Broadcaster using the #PathParam annotation:
private
#PathParam("topic")
Broadcaster topic;
You can also use the #Context annotation. Hope that help.
-- Jeanfrancois
Please, at least pseudo (but from working environment not "maybe this should work") application context and controller/filter that will authenticate and/or auto-register Facebook users.
This link: http://blog.kadirpekel.com/2009/11/09/facebook-connect-integration-with-spring-security/ will not do. Actually I will put minus point to anyone who will post it as answer. I spend 2 hours with the thing and I didn't get it to work. I ended bit more bolder and feeling more stupid than usual after this endeavor :-(
I would really like to see OAuth 2.0 solution for facebook connect. And restrict the use of Facebook JavaScript API to absolute minimum.
Following link shows about what I need:
http://www.richardnichols.net/2010/06/implementing-facebook-oauth-2-0-authentication-in-java/
Please post only code to this question. I already got all the advice I can handle.
UPDATE
I have servlet solution and posted answer here if anyone is interested:
Facebook Connect example in JSP (tomcat)
Here's an MVC implementation of facebook OAuth 2.0
The code's in C# and hopefully its similarity with java helps you out.
Controller(Entry point):Controller(in MVC) is the point in the code where the control reaches after someone clicks on the login link.
public ActionResult Authenticate()
{
var oauthFacebook = new FacebookOAuth();
if (Request["code"] == null)
{
//Redirect the user to Facebook for authorization.
Response.Redirect(oauthFacebook.AuthorizationLinkGet());
}
else
{
//Get the access token and secret.
oauthFacebook.AccessTokenGet(Request["code"]);
if (oauthFacebook.Token.Length > 0)
{
//We can now make our api calls
var user = oauthFacebook.GetAttributes();
}
}
}
FacebookOAuth Class
public class FacebookOAuth : Oauth
{
public FacebookOAuth()
{
Authorize = "https://graph.facebook.com/oauth/authorize";
AccessToken = "https://graph.facebook.com/oauth/access_token";
CallbackUrl = "http://<YourURLHere>/Authenticate";
AttributesBaseUrl = "https://graph.facebook.com/me/?access_token=";
ConsumerKey = ConfigurationManager.AppSettings["FacebookConsumerKey"];//Ur Consumer Key goes here
ConsumerSecret = ConfigurationManager.AppSettings["FacebookConsumerSecret"];//Ur Consumer secret goes here
Provider = "Facebook";
}
public override string AuthorizationLinkGet()
{
return
string.Format(
"{0}?client_id={1}&redirect_uri={2}&scope=email,user_education_history,user_location,user_hometown",
Authorize, ConsumerKey, CallbackUrl);
}
public User GetAttributes()
{
string attributesUrl = string.Format("{0}{1}", AttributesBaseUrl, Token);
string attributes = WebRequest(Method.Get, attributesUrl, String.Empty);
var FacebookUser = new JavaScriptSerializer().Deserialize<FacebookUser>(attributes);
return new User()
{
FirstName = FacebookUser.first_name,
MiddleName = FacebookUser.middle_name,
LastName = FacebookUser.last_name,
Locale = FacebookUser.locale,
UserEmail = FacebookUser.email,
AuthProvider = Provider,
AuthToken=Token
};
}
}
OAuth baseclass(Class from which FacebookOAuth derives)
public abstract class Oauth
{
#region Method enum
public enum Method
{
Get,
Post,
Delete
} ;
#endregion
protected string AccessToken;
protected string AttributesBaseUrl;
protected string Authorize;
protected string CallbackUrl;
protected string ConsumerKey;
protected string ConsumerSecret;
public string Provider { get; protected set; }
public string Token { get; set; }
public virtual string AuthorizationLinkGet()
{
return
string.Format(
"{0}?client_id={1}&redirect_uri={2}&scope=publish_stream,email,user_education_history,user_location",
Authorize, ConsumerKey, CallbackUrl);
}
public void AccessTokenGet(string authToken)
{
Token = authToken;
string accessTokenUrl = string.Format("{0}?client_id={1}&redirect_uri={2}&client_secret={3}&code={4}",
AccessToken, ConsumerKey, CallbackUrl, ConsumerSecret, authToken);
string response = WebRequest(Method.Get, accessTokenUrl, String.Empty);
if (response.Length > 0)
{
//Store the returned access_token
NameValueCollection qs = HttpUtility.ParseQueryString(response);
if (qs["access_token"] != null)
{
Token = qs["access_token"];
}
}
}
public string WebRequest(Method method, string url, string postData)
{
StreamWriter requestWriter;
string responseData = string.Empty;
var webRequest = System.Net.WebRequest.Create(url) as HttpWebRequest;
if (webRequest != null)
{
webRequest.Method = method.ToString();
webRequest.ServicePoint.Expect100Continue = false;
webRequest.Timeout = 20000;
if (method == Method.Post)
{
webRequest.ContentType = "application/x-www-form-urlencoded";
//POST the data.
requestWriter = new StreamWriter(webRequest.GetRequestStream());
try
{
requestWriter.Write(postData);
}
finally
{
requestWriter.Close();
}
}
responseData = WebResponseGet(webRequest);
}
return responseData;
}
public string WebResponseGet(HttpWebRequest webRequest)
{
StreamReader responseReader = null;
string responseData;
try
{
responseReader = new StreamReader(webRequest.GetResponse().GetResponseStream());
responseData = responseReader.ReadToEnd();
}
finally
{
if (webRequest != null) webRequest.GetResponse().GetResponseStream().Close();
if (responseReader != null) responseReader.Close();
}
return responseData;
}
}
I actually just finished my non-javascript, implementation of the Facebook Graph API Authentication last night. I was a gargantuan pain in the a**, but it works and it's working fairly well.
I used the example from the link you posted above as a starting point, as well as, the code from here as a starting point. I had to write my own implementation of their FacebookGraphAuthenticationProvider and their FacebookGraphAuthenticationFilter, but now it works the way I want it to.
You need to create implementations of both of these files, put your filter in the filter chain, and create a implementation of the Spring Security UserDetailsService that the Provider can use to manage your user account information. I have some code on my machine at home that I can send you via email if you like.
Here are the steps I had to use to get the authentication to work:
Get an "code" for a user, this is done by making the following call: https://www.facebook.com/dialog/oauth?client_id=YOUR_APP_ID&redirect_uri=YOUR_URL&scope=email,read_stream (The scope is all the permissions you want to request from FB). This call will create an "authentication code" which will then be sent back to your "redirect_uri" (which I stated as http://{my fb app registered domain}/j_spring_security_authentication_check.
Once you have this "code", you need to make a call within your AuthenticationProvider that will retrieve an access_token for your user's session: this URL looks like: https://graph.facebook.com/oauth/access_token? client_id=YOUR_APP_ID&redirect_uri=YOUR_URL&client_secret=YOUR_APP_SECRET&code=THE_CODE_FROM_ABOVE. You have to make sure your "redirect_uri" is the same as the one you did in #1. You'll make the above call using something like Apache's HttpClient, or the like.
Now with this access_token (which comes in the body of above response), you can get your user's profile information with the following URL: https://graph.facebook.com/me?access_token={ACCESS_TOKEN from above). The response will be in JSON. You can also use the access_token with all of the graph API to post status, pictures, etc.
I have some code at home that has my full implementation that I would be happy to share.
I hope this helps at least a bit. I suggest using the Spring Social app to get started with posting status, pictures, wall stuff, etc. This will be a good place to start looking at FB-Spring interaction.