项目作者: acailic

项目描述 :
REST service with Spring HATEOAS and Oauth2
高级语言: Java
项目地址: git://github.com/acailic/readingmeter.git
创建时间: 2017-12-19T14:49:45Z
项目社区:https://github.com/acailic/readingmeter

开源协议:

下载


Spring Hateoas

Spring Hateoas

tags: [rest, hateoas, hypermedia, security, testing, oauth]
projects: [spring-framework, spring-hateoas, spring-security, spring-security-oauth]

Reading meter

REST service with Spring HATEOAS and Spring security Oauth

Hypermedia-driven REST service with Spring HATEOAS, a library of APIs that you can use to easily create links pointing to Spring MVC controllers, build up resource representations, and control how they’re rendered into supported hypermedia formats such as HAL.
we�re going to build a web application, using jpa to model records in an h2 database.[Web, JPA, H2]

The service will accept HTTP requests at:

  1. http://localhost:8080/connections GET POST
  2. http://localhost:8080/connections/{connectionId} GET PUT DELETE
  3. http://localhost:8080/profiles GET POST
  4. http://localhost:8080/profiles/{profileId} GET PUT DELETE
  5. http://localhost:8080/consumptions/{consumptionMonth} GET
  6. http://localhost:8080/consumptions/{consumptionMonth}/{connectionId} GET

and respond with a link:/understanding/JSON[JSON] representation of a greeting enriched with the simplest possible hypermedia element, a link pointing to the resource itself:

Improved Error Handling with VndErrors

HATEOAS gives clients improved metadata about the service itself. We can improve the situation for our error handling, as well. HTTP status codes tell the client - broadly - that something went wrong. HTTP status codes from 400-499, for example, tell the client that the client did something wrong. HTTP status codes from 500-599 tell the client that the server did something wrong. If you know your status codes, then this can be a start in understanding how to work with the API. But, we can do better. After all, before a REST client is up and running, somebody needs to develop it, and useful error messages can be invaluable in understanding an API.
Errors that can be handled in a consistent way are even better.

Client Authentication and Authorization on the Open Web with Spring Security OAuth

We can authenticate client requests in a myriad of ways. Clients could send, for example, an HTTP-basic username and password on each request. They could transmit an x509 certificate on each request. There are indeed numerous approaches that could be used here, with numerous tradeoffs.

Our API is meant to be consumed over the open-web. It’s meant to be used by all manner of HTML5 and native mobile and desktop clients that we intend to build. We shall use diverse clients with diverse security capabilities, and any solution we pick should be able to accommodate that. We should also decouple the user’s username and password from the application’s session.
The OAuth2Configuration configuration class describes one client (here, one for a hypothetical Android client) that needs the ROLE_USER and the write scope. Spring Security OAuth will read this information from the AuthenticationManager that is ultimately configured using our custom UserDetailsService implementation.
We can explicitly enable XSS for well-known clients by exposing CORS (cross-origin request scripting) headers. These headers, when present in the service responses, signal to the browser that requests of the origin, shape and configuration described in the headers are permitted, even across domains.
Using HTTPS (SSL/TLS) to prevent Man-in-the-Middle Attacks:security/src/main/resources/application-https.properties. the app is run when SPRING_PROFILES_ACTIVE configured with profile https.
requires a signed certificate certificate and a certificate password : $ keytool -genkey -alias bookmarks -keyalg RSA -keystore src/main/resources/tomcat.keystore

Testing a REST Service, the following:

Spring MVC provides support for unit testing HTTP endpoints.

http://localhost:8080/connections/1 GET

  1. {
  2. "connection": {
  3. "id": 1,
  4. "profile": {
  5. "name": "B"
  6. },
  7. "meterReading": [
  8. {
  9. "month": "OCT",
  10. "meterReading": 10
  11. },
  12. {
  13. "month": "APR",
  14. "meterReading": 4
  15. },
  16. {
  17. "month": "AUG",
  18. "meterReading": 8
  19. },
  20. {
  21. "month": "MAR",
  22. "meterReading": 3
  23. },
  24. {
  25. "month": "MAY",
  26. "meterReading": 5
  27. },
  28. {
  29. "month": "FEB",
  30. "meterReading": 2
  31. },
  32. {
  33. "month": "NOV",
  34. "meterReading": 11
  35. },
  36. {
  37. "month": "JUL",
  38. "meterReading": 7
  39. },
  40. {
  41. "month": "JAN",
  42. "meterReading": 1
  43. },
  44. {
  45. "month": "JUN",
  46. "meterReading": 6
  47. },
  48. {
  49. "month": "DEC",
  50. "meterReading": 12
  51. },
  52. {
  53. "month": "SEP",
  54. "meterReading": 9
  55. }
  56. ],
  57. "uri": "http://connection.com/1/"
  58. },
  59. "_links": {
  60. "connection-uri": {
  61. "href": "http://connection.com/1/"
  62. },
  63. "connections": {
  64. "href": "http://localhost:8080/connections"
  65. },
  66. "self": {
  67. "href": "http://localhost:8080/connections/1"
  68. }
  69. }
  70. }

http://localhost:8080/profiles/1 GET

  1. {
  2. "_embedded": {
  3. "profileResourceList": [
  4. {
  5. "profile": {
  6. "id": 1,
  7. "name": "A",
  8. "fractions": [
  9. {
  10. "month": "JUL",
  11. "fraction": 0
  12. },
  13. {
  14. "month": "JUN",
  15. "fraction": 0
  16. },
  17. {
  18. "month": "MAY",
  19. "fraction": 0.1
  20. },
  21. { http://localhost:8080/profiles/1 GET
  22. "month": "JAN",
  23. "fraction": 0.1
  24. },
  25. {
  26. "month": "OCT",
  27. "fraction": 0.1
  28. },
  29. {
  30. "month": "SEP",
  31. "fraction": 0.1
  32. },
  33. {
  34. "month": "APR",
  35. "fraction": 0.1
  36. },
  37. {
  38. "month": "AUG",
  39. "fraction": 0.1
  40. },
  41. {
  42. "month": "MAR",
  43. "fraction": 0.1
  44. },
  45. {
  46. "month": "FEB",
  47. "fraction": 0.1
  48. },
  49. {
  50. "month": "DEC",
  51. "fraction": 0.1
  52. },
  53. {
  54. "month": "NOV",
  55. "fraction": 0.1
  56. }
  57. ],
  58. "uri": "http://profile.com/1/\""
  59. },
  60. "_links": {
  61. "profile-uri": {
  62. "href": "http://profile.com/1/\""
  63. },
  64. "profiles": {
  65. "href": "http://localhost:8080/profiles"
  66. },
  67. "self": {
  68. "href": "http://localhost:8080/profiles/1"
  69. }
  70. }
  71. }
  72. }

http://localhost:8080/consumptions/JAN GET

  1. {
  2. "_embedded": {
  3. "consumptionResourceList": [
  4. {
  5. "consumption": {
  6. "month": "JAN",
  7. "consumption": 1,
  8. "uri": "http://connection.com/1//consumptions/JAN"
  9. },
  10. "_links": {
  11. "consumption-uri": {
  12. "href": "http://connection.com/1//consumptions/JAN"
  13. },
  14. "consumptions": {
  15. "href": "http://localhost:8080/consumptions/JAN"
  16. },
  17. "self": {
  18. "href": "http://localhost:8080/consumptions/JAN/1"
  19. }
  20. }
  21. },
  22. {
  23. "consumption": {
  24. "month": "JAN",
  25. "consumption": 1,
  26. "uri": "http://connection.com/1//consumptions/JAN"
  27. },
  28. "_links": {
  29. "consumption-uri": {
  30. "href": "http://connection.com/1//consumptions/JAN"
  31. },
  32. "consumptions": {
  33. "href": "http://localhost:8080/consumptions/JAN"
  34. },
  35. "self": {
  36. "href": "http://localhost:8080/consumptions/JAN/1"
  37. }
  38. }
  39. }
  40. ]
  41. }
  42. }

Future tasks: Pagination to add (already in repositories)
entity-uri is just for simulation.

Resources