使用curl测试Grails Spring Security Rest时遭遇401未授权问题
Hey there, let's break down how to track down and fix that 401 error you're seeing with your custom Spring Security setup. I'll walk through the most likely issues step by step:
Step 1: Double-Check Core User Lookup Configuration
Since you renamed username to emailAddress on your AdminAccount domain, this is the first place to verify. Your application.groovy Spring Security config needs to explicitly tell the plugin to use emailAddress as the login identifier. Make sure these settings are present and correct:
grails { plugin { springsecurity { // Keep this if using InterceptUrlMap; adjust if using annotation-based security securityConfigType = "InterceptUrlMap" // Core user/role mapping config userLookup { userDomainClassName = 'your.package.AdminAccount' usernamePropertyName = 'emailAddress' // Critical: matches your custom field enabledPropertyName = 'enabled' passwordPropertyName = 'password' } authority { className = 'your.package.Role' nameField = 'authority' // e.g., 'ROLE_ADMIN' } authorityJoinClassName = 'your.package.AdminAccountRole' // Link between AdminAccount and Role permission { className = 'your.package.Permission' nameField = 'name' // e.g., 'USER_CREATE' } permissionJoinClassName = 'your.package.RolePermission' // Link between Role and Permission } } }
If any of these are missing or point to the wrong domain/class names, the auth system won't find your user or their permissions.
Step 2: Validate Spring Security Rest Request Format
The Rest plugin expects specific request data for login. If your curl command is using username instead of emailAddress, that's a guaranteed 401. Here's the correct curl syntax for your setup:
curl -X POST -H "Content-Type: application/json" -d '{"emailAddress": "your-admin-email@example.com", "password": "your-encrypted-password"}' http://localhost:8080/api/login
A few key notes:
- The request must be
POSTto the default/api/loginendpoint (adjust if you've customized the path) - The
Content-Typeheader must beapplication/json - You're sending
emailAddress(notusername) as the login field
Step 3: Confirm Database & Test Data Correctness
Even if your config is right, bad test data will cause 401s:
- Passwords must be encrypted: Spring Security Core uses BCrypt by default. Never store plaintext passwords. Use the
encodePasswordmethod from the plugin to generate hashes, e.g., inBootstrap.groovy:def springSecurityService def init = { servletContext -> def admin = new AdminAccount(emailAddress: 'admin@example.com', password: springSecurityService.encodePassword('secure123')).save(flush: true) // Link admin to roles and roles to permissions here } - Verify permission chain: Ensure your
AdminAccountis linked to aRole, which is linked to at least onePermissionvia the join tables (AdminAccountRole,RolePermission). A user with no roles/permissions might get a 401 if your intercept rules require specific access.
Step 4: Enable Debug Logging to See the Root Cause
If the above steps don't fix it, turn on debug logging to see exactly where the auth flow fails. Update your logback.groovy to add:
logger("org.springframework.security", DEBUG, ["STDOUT"], false) logger("grails.plugin.springsecurity", DEBUG, ["STDOUT"], false)
Restart your app and run the curl command again. Look for log lines like:
User not found: your-email@example.com(plugin can't find the user viaemailAddress)Bad credentials(password mismatch or plaintext password used)Access is denied(user exists but lacks required permissions)
These logs will point you directly to the issue.
Step 5: Check CSRF Configuration
By default, the Spring Security Rest plugin disables CSRF protection for the login endpoint, but if you've modified CSRF settings, this could block your request. Ensure this line is present if needed:
grails.plugin.springsecurity.csrf.enabled = false // Or adjust if you need CSRF for other endpoints
Step 6: Validate Custom Domain Class Mappings
Make sure your custom domain classes have correct GORM associations. For example, your AdminAccount should look something like this:
class AdminAccount { String emailAddress String password boolean enabled = true static hasMany = [roles: Role] static mapping = { password column: '`password`' // Escape reserved word if needed roles joinTable: [name: 'admin_account_role', key: 'admin_account_id', column: 'role_id'] } static constraints = { emailAddress unique: true, nullable: false password nullable: false } }
Incorrect join table mappings will break the plugin's ability to fetch user roles and permissions, leading to authorization failures.
内容的提问来源于stack exchange,提问作者Rut

