-
-
Save joseraya/176821d856b43b1cfe19 to your computer and use it in GitHub Desktop.
package com.agilogy.spray.cors | |
import spray.http.{HttpMethods, HttpMethod, HttpResponse, AllOrigins} | |
import spray.http.HttpHeaders._ | |
import spray.http.HttpMethods._ | |
import spray.routing._ | |
// see also https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS | |
trait CORSSupport { | |
this: HttpService => | |
private val allowOriginHeader = `Access-Control-Allow-Origin`(AllOrigins) | |
private val optionsCorsHeaders = List( | |
`Access-Control-Allow-Headers`("Origin, X-Requested-With, Content-Type, Accept, Accept-Encoding, Accept-Language, Host, Referer, User-Agent"), | |
`Access-Control-Max-Age`(1728000)) | |
def cors[T]: Directive0 = mapRequestContext { ctx => ctx.withRouteResponseHandling({ | |
//It is an option requeset for a resource that responds to some other method | |
case Rejected(x) if (ctx.request.method.equals(HttpMethods.OPTIONS) && !x.filter(_.isInstanceOf[MethodRejection]).isEmpty) => { | |
val allowedMethods: List[HttpMethod] = x.filter(_.isInstanceOf[MethodRejection]).map(rejection=> { | |
rejection.asInstanceOf[MethodRejection].supported | |
}) | |
ctx.complete(HttpResponse().withHeaders( | |
`Access-Control-Allow-Methods`(OPTIONS, allowedMethods :_*) :: allowOriginHeader :: | |
optionsCorsHeaders | |
)) | |
} | |
}).withHttpResponseHeadersMapped { headers => | |
allowOriginHeader :: headers | |
} | |
} | |
} |
val routes: Route = | |
cors { | |
path("hello") { | |
get { | |
complete { | |
"GET" | |
} | |
} ~ | |
put { | |
complete { | |
"PUT" | |
} | |
} | |
} | |
} |
Hi,
I've been trying to get the CORSSupport class to work with Basic Authentication but I'm not getting anywhere fast.
I've added Authorization to the list of supported classes but with my implementation the CORSSupport class doesn't seem to get called at all. It seems almost like the Authorization response is handled separately and never executes the CORS header class as the result I always get back is a 401 with the message that no origin header was present in the response.
Does anyone have any pointers on how to use CORS with Basic Auth?
My route looks like follows...
pathPrefix("v1") {
cors {
pathPrefix("test") {
authenticate(BasicAuth(ClientAuthentication, "API Authentication")) {
customerProfile =>
get {
respondWithMediaType(application/json
){
complete("""{"result": "test!"}""")
}
}
}
}
}
Thanks
Ignore above comment. Got it working by adding the following to the CORSSupport class...
|| (ctx.request.method.equals(HttpMethods.OPTIONS)
&& x.exists(_.isInstanceOf[AuthenticationFailedRejection]))
as well as adding "Authorization" to the list of headers
Thanks
This is my implementation:
class MyServiceActor extends Actor with MyService {
def actorRefFactory = context
def requestMethodAndResponseStatusAsInfo(req: HttpRequest): Any => Option[LogEntry] = {
case res: HttpResponse => Some(LogEntry(req.method + ":" + req.uri + ":" + res.message.status, InfoLevel))
case _ => None // other kind of responses
}
def routeWithLogging = logRequestResponse(requestMethodAndResponseStatusAsInfo _)(myRoute ~ testRoute)
def receive = runRoute(routeWithLogging)
}
// this trait defines our service behavior independently from the service actor
trait MyService extends HttpService {
implicit val rejectHandler = RejectionHandler {
case MissingQueryParamRejection(paramName) :: _ => ctx
=> ctx.complete(APIresponse.errorResponse(s"Parameter ' $paramName ' is missing", 404))
case MissingFormFieldRejection(paramName) :: _ => ctx
=> ctx.complete(APIresponse.errorResponse(s"Parameter ' $paramName ' is missing", 404))
}
private val allowOriginHeader = Access-Control-Allow-Origin
(AllOrigins)
private val optionsCorsHeaders = List(
Access-Control-Allow-Headers
("Origin, X-Requested-With, Content-Type, Accept, Accept-Encoding, Accept-Language, Host, Referer, User-Agent"),
Access-Control-Max-Age
(1728000))
def cors[T]: Directive0 = mapRequestContext { ctx => ctx.withRouteResponseHandling({
//It is an option requeset for a resource that responds to some other method
case Rejected(x) if (ctx.request.method.equals(HttpMethods.OPTIONS) && !x.filter(_.isInstanceOf[MethodRejection]).isEmpty) => {
val allowedMethods: List[HttpMethod] = x.filter(_.isInstanceOf[MethodRejection]).map(rejection=> {
rejection.asInstanceOf[MethodRejection].supported
})
ctx.complete(HttpResponse().withHeaders(
`Access-Control-Allow-Methods`(OPTIONS, allowedMethods :_*) :: allowOriginHeader ::
optionsCorsHeaders
))
}
}).withHttpResponseHeadersMapped { headers =>
allowOriginHeader :: headers
}
}
val userLogic = new UserMgmtLOGIC
var response = new String
val myRoute: Route =
path("api" / "user-service") {
get {
ctx => ctx.complete(APIresponse.successResponese(null, "Welcome to User Management Service"))
}
} ~ cors {
path("api" / "user-service" / "create-user") {
post {
formFields('email, 'user_name, 'password, 'role?) {(email, user_name, password, role) =>
if(email.isEmpty()){
ctx => ctx.complete(APIresponse.errorResponse("Email field is empty"))
}else if(password.isEmpty()){
ctx => ctx.complete(APIresponse.errorResponse("Password field is empty"))
}else if(user_name.isEmpty()){
ctx => ctx.complete(APIresponse.errorResponse("User Name field is empty"))
}else{
val userData = Map("email" -> email, "user_name" -> user_name, "password" -> password, "role" -> role)
var payload = userData.asInstanceOf[Map[String, Any]]
response = userLogic.createUserRecord(payload)
ctx => ctx.complete(response)
}
}
}
}
} ~ path("api" / "user-service" / "delete-user") {
get {
parameter('email){(email) =>
response = userLogic.deleteUserRecord(email)
ctx => ctx.complete(response)
}
}
} ~ path("api" / "user-service" / "all-users") {
get {
response = userLogic.getAllUsers()
ctx => ctx.complete(response)
}
} ~
cors {
path("api" / "user-service" / "login") {
post {
formFields('username, 'password) {(username, password) =>
if(username.isEmpty()){
ctx => ctx.complete(APIresponse.errorResponse("Email field is empty"))
}else if(password.isEmpty()){
ctx => ctx.complete(APIresponse.errorResponse("Password field is empty"))
}else{
response = userLogic.userLogin(username, password)
ctx => ctx.complete(response)
}
}
}
}
} ~ path("api" / "user-service" / "test") {
get {
respondWithMediaType(application/json
) {
respondWithHeader(RawHeader("Access-Control-Allow-Origin","*")) {
ctx => ctx.complete("""{"name" : "olalekan"}""")
}
}
}
}
}
Can anyone help?
I have the following problem:
To compile the project shows me this:
WidgetService.scala:21: illegal inheritance;
[error] self-type api.WidgetService does not conform to lib.CORSSupport's selftype lib.CORSSupport with spray.routing.HttpService
[error] actorRefFactory: ActorRefFactory) extends RoutedEndpoints with WidgetHandler with UtilBijections with CORSSupport{
The solution may be this:
https://www.safaribooksonline.com/library/view/scala-cookbook/9781449340292/ch08s07.html
I do not get it to work:
What options do I have to fix it? Thanks
my code is here:
https://gist.github.com/hectorgool/df2acef9e82f54de1822