I am trying to create a REST api for user editing.
I decided to use approach described in documentation:
https://docs.grails.org/3.3.11/guide/REST.html#domainResources (I am using older grailsVersion=3.3.11)
So I went ahead and I created the domain class like this (domain class was created by command grails s2-quickstart com.mastiko.auth User Role)
package com.mastiko.auth
import grails.rest.Resource
@Resource(uri = '/api/users', formats=['json'])
class User implements Serializable {
private static final long serialVersionUID = 1
String username
String password
String mems****ApiUser
String mems****ApiPassword
boolean enabled = true
boolean accountExpired
boolean accountLocked
boolean passwordExpired
Set<Role> getAuthorities() {
(UserRole.findAllByUser(this) as List<UserRole>)*.role as Set<Role>
}
static constraints = {
password nullable: false, blank: false, password: true
username nullable: false, blank: false, unique: true
}
static mapping = {
password column: '`password`'
}
}
My application.groovy looks like this:
// Added by the Spring Security Core plugin:
grails.plugin.springsecurity.userLookup.userDomainClassName = 'com.mastiko.auth.User'
grails.plugin.springsecurity.userLookup.authorityJoinClassName = 'com.mastiko.auth.UserRole'
grails.plugin.springsecurity.authority.className = 'com.mastiko.auth.Role'
grails.plugin.springsecurity.controllerAnnotations.staticRules = [
[pattern: '/', access: ['permitAll']],
[pattern: '/dbconsole/**', access: ['permitAll']],
[pattern: '/error', access: ['permitAll']],
[pattern: '/index', access: ['permitAll']],
[pattern: '/index.gsp', access: ['permitAll']],
[pattern: '/shutdown', access: ['permitAll']],
[pattern: '/assets/**', access: ['permitAll']],
[pattern: '/**/js/**', access: ['permitAll']],
[pattern: '/**/css/**', access: ['permitAll']],
[pattern: '/**/images/**', access: ['permitAll']],
[pattern: '/**/favicon.ico', access: ['permitAll']]
]
grails.plugin.springsecurity.filterChain.chainMap = [
[pattern: '/assets/**', filters: 'none'],
[pattern: '/**/js/**', filters: 'none'],
[pattern: '/**/css/**', filters: 'none'],
[pattern: '/**/images/**', filters: 'none'],
[pattern: '/**/favicon.ico', filters: 'none'],
[pattern: '/**', filters: 'JOINED_FILTERS']
]
Also, I added this configuration into application.yml, as I wasnt able to make the spring security rest api plugin work without it
plugin:
springsecurity:
controllerAnnotations:
chainMap:
'/api/**': 'JOINED_FILTERS,-anonymousAuthenticationFilter,-exceptionTranslationFilter,-authenticationProcessingFilter,-securityContextPersistenceFilter'
'/**': 'JOINED_FILTERS,-restTokenValidationFilter,-restExceptionTranslationFilter'
My UrlMappings.groovy:
package mems****eprojects (censored)
class UrlMappings {
static mappings = {
delete "/$controller/$id(.$format)?"(action:"delete")
get "/$controller(.$format)?"(action:"index")
get "/$controller/$id(.$format)?"(action:"show")
post "/$controller(.$format)?"(action:"save")
put "/$controller/$id(.$format)?"(action:"update")
patch "/$controller/$id(.$format)?"(action:"patch")
"/"(controller: 'application', action:'index')
}
}
Now, when I try to access my api using POST request to http://localhost:8080/api/users, I always get 404 not found response:
{
"timestamp": 1598893213831,
"status": 404,
"error": "Not Found",
"message": "No message available",
"path": "/api/users"
}
I tried a command grails url-mappings-report, and I get a positive result:
Dynamic Mappings
| GET | /${controller}(.${format)? | Action: index |
| POST | /${controller}(.${format)? | Action: save |
| DELETE | /${controller}/${id}(.${format)? | Action: delete |
| GET | /${controller}/${id}(.${format)? | Action: show |
| PUT | /${controller}/${id}(.${format)? | Action: update |
| PATCH | /${controller}/${id}(.${format)? | Action: patch |
Controller: application
| * | / | Action: index |
Controller: restOauth
| * | /oauth/access_token | Action: accessToken |
| * | /oauth/${action}/${provider} | Action: (default action) |
Controller: user
| GET | /api/users/create | Action: create |
| GET | /api/users/${id}/edit | Action: edit |
| POST | /api/users | Action: save |
| GET | /api/users | Action: index |
| DELETE | /api/users/${id} | Action: delete |
| PATCH | /api/users/${id} | Action: patch |
| PUT | /api/users/${id} | Action: update |
| GET | /api/users/${id} | Action: show |
I am pretty new into grails and this is my very first application.
I am sorry if some important part of code is missing, I will post it if needed. Can you please help me? I was trying to figure this out for hours now..
//edit 1 I forgot to add my build.gradle
buildscript {
repositories {
mavenLocal()
maven { url "https://repo.grails.org/grails/core" }
maven { url "https://plugins.gradle.org/m2/" }
}
dependencies {
classpath "org.grails:grails-gradle-plugin:$grailsVersion"
classpath "com.moowork.gradle:gradle-node-plugin:1.2.0"
classpath "org.grails.plugins:hibernate5:${gormVersion-".RELEASE"}"
classpath "org.grails.plugins:views-gradle:1.2.9"
}
}
version "0.1"
group "mem****eprojects"
apply plugin:"eclipse"
apply plugin:"idea"
apply plugin:"war"
apply plugin:"org.grails.grails-web"
apply plugin:"com.moowork.node"
apply plugin:"org.grails.plugins.views-json"
repositories {
mavenLocal()
maven { url "https://repo.grails.org/grails/core" }
}
dependencies {
compile "org.springframework.boot:spring-boot-starter-logging"
compile "org.springframework.boot:spring-boot-autoconfigure"
compile "org.grails:grails-core"
compile "org.springframework.boot:spring-boot-starter-actuator"
compile "org.springframework.boot:spring-boot-starter-tomcat"
compile "org.grails:grails-plugin-url-mappings"
compile "org.grails:grails-plugin-rest"
compile "org.grails:grails-plugin-codecs"
compile "org.grails:grails-plugin-interceptors"
compile "org.grails:grails-plugin-services"
compile "org.grails:grails-plugin-datasource"
compile "org.grails:grails-plugin-databinding"
compile "org.grails:grails-web-boot"
compile "org.grails:grails-logging"
compile "org.grails.plugins:cache"
compile "org.grails.plugins:async"
compile "org.grails.plugins:hibernate5"
compile "org.hibernate:hibernate-core:5.1.16.Final"
compile "org.grails.plugins:views-json"
compile "org.grails.plugins:views-json-templates"
compile "org.grails.plugins:spring-security-core:3.2.0"
compile "org.grails.plugins:spring-security-rest:2.0.0.M2"
console "org.grails:grails-console"
profile "org.grails.profiles:vue"
runtime "org.glassfish.web:el-impl:2.1.2-b03"
runtime "com.h2database:h2"
runtime "org.apache.tomcat:tomcat-jdbc"
testCompile "org.grails:grails-gorm-testing-support"
testCompile "org.grails:grails-datastore-rest-client"
testCompile "org.grails:grails-web-testing-support"
}
bootRun {
jvmArgs('-Dspring.output.ansi.enabled=always')
addResources = true
String springProfilesActive = 'spring.profiles.active'
systemProperty springProfilesActive, System.getProperty(springProfilesActive)
}
I added spring-security-rest plugin to be able to authenticate myself from my vuejs frontend using /api/login endpoint. I retrieve the token, and then I am trying to make request to /api/users endpoint with the token in header. So maybe the issue is maybe caused by this plugin
So I was able to fix this removing code bellow from application.yml
plugin:
springsecurity:
controllerAnnotations:
chainMap:
'/api/**': 'JOINED_FILTERS,-anonymousAuthenticationFilter,-exceptionTranslationFilter,-authenticationProcessingFilter,-securityContextPersistenceFilter'
'/**': 'JOINED_FILTERS,-restTokenValidationFilter,-restExceptionTranslationFilter'
and adding code bellow to application.groovy
grails.plugin.springsecurity.filterChain.chainMap = [
//Stateless chain
[ pattern: '/api/**', filters: 'JOINED_FILTERS,-anonymousAuthenticationFilter,-exceptionTranslationFilter,-authenticationProcessingFilter,-securityContextPersistenceFilter,-rememberMeAuthenticationFilter'],
//Traditional chain
//[ pattern: '/**', filters: 'JOINED_FILTERS,-restTokenValidationFilter,-restExceptionTranslationFilter']
]
I am not really sure why I put chainMap in application.yml in the first place.
Thank you for reading this and tryhing to help me
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.