登录成功(api/login),增加登录日志
package middol.auth
import grails.converters.JSON
import grails.plugin.springsecurity.rest.token.AccessToken
import grails.plugin.springsecurity.rest.token.rendering.AccessTokenJsonRenderer
import grails.plugin.springsecurity.userdetails.GrailsUser
import groovy.util.logging.Slf4j
import middol.logs.LoginRecord
import org.springframework.security.core.Authentication
import org.springframework.security.web.authentication.AuthenticationSuccessHandler
import javax.servlet.ServletException
import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpServletResponse
import static grails.async.Promises.task
/**
* @Description: 登录成功--生成登录日志
* @Author: zhangjiayu@middol.com
* @CreateDate: 2020/7/21 9:56
* @Version: 1.0
*/
@Slf4j
class MiddolAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
AccessTokenJsonRenderer renderer
@Override
void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
log.info("登陆成功:${authentication as JSON}")
if (authentication.principal instanceof GrailsUser) {
GrailsUser user = ((GrailsUser) (authentication.principal))
log.info("用户信息:${user as JSON}")
// User sysUser = User.findByUsername(user.username)
// sysUser.logerror = 0d
// sysUser.save(flush: true)
log.info("detail:${authentication?.accessToken}")
//记录登陆日志
task {
LoginRecord.withTransaction {
LoginRecord loginrecord = new LoginRecord()
loginrecord.login_ip = request.getRemoteHost()
loginrecord.login_username = user.username
// loginrecord.login_token = authentication?.accessToken
loginrecord.login_indate = new Date()
loginrecord.login_http = request.getMethod()
if (!loginrecord.hasErrors()) {
log.info("保存登陆日志:${loginrecord.toString()}")
loginrecord.save(flush: true)
} else {
log.info("日志错误:${loginrecord.errors?.toString()}")
}
}
}
}
response.contentType = 'application/json'
response.characterEncoding = 'UTF-8'
response.addHeader 'Cache-Control', 'no-store'
response.addHeader 'Pragma', 'no-cache'
response << renderer.generateJson(authentication as AccessToken)
}
}
2、登录失败(401)
package middol.auth
import grails.converters.JSON
import groovy.transform.CompileStatic
import groovy.util.logging.Slf4j
import middol.result.ResultCodeEnum
import middol.result.ResultUtils
import org.springframework.security.core.AuthenticationException
import org.springframework.security.web.authentication.AuthenticationFailureHandler
import javax.servlet.ServletException
import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpServletResponse
/**
* @Description: 登录失败--记录到登录日志里面
* @Author: zhangjiayu@middol.com
* @CreateDate: 2020/7/21 9:58
* @Version: 1.0
*/
@Slf4j
@CompileStatic
class MiddolAuthenticationFailureHandler implements AuthenticationFailureHandler {
Integer statusCode
@Override
void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
log.debug("auth error:${exception.message}")
log.debug "Setting status code to ${statusCode}"
response.setStatus(statusCode)
response.addHeader('WWW-Authenticate', 'Bearer')
response.setContentType("application/json;charset=utf-8")
response << (ResultUtils.error(statusCode?.toString(), exception.message) as JSON)
}
}
3、登录成功自定义返回格式
package middol.auth
import grails.converters.JSON
import grails.plugin.springsecurity.rest.oauth.OauthUser
import grails.plugin.springsecurity.rest.token.AccessToken
import grails.plugin.springsecurity.rest.token.rendering.AccessTokenJsonRenderer
import groovy.transform.CompileStatic
import groovy.util.logging.Slf4j
import middol.result.ResultUtils
import org.pac4j.core.profile.CommonProfile
import org.springframework.security.core.GrantedAuthority
import org.springframework.security.core.userdetails.UserDetails
import org.springframework.util.Assert
@Slf4j
@CompileStatic
/**
* @Description: 自定义登录返回格式
* @Author: zhangjiayu@middol.com
* @CreateDate: 2020/7/21 0:54
* @Version: 1.0
*/
class MiddolAccessTokenJsonRenderer implements AccessTokenJsonRenderer {
String usernamePropertyName
String tokenPropertyName
String authoritiesPropertyName
Boolean useBearerToken
String generateJson(AccessToken accessToken) {
Assert.isInstanceOf(UserDetails, accessToken.principal, "A UserDetails implementation is required")
UserDetails userDetails = accessToken.principal as UserDetails
Map result = [
"userInfo" : userDetails,
(authoritiesPropertyName) : accessToken.authorities.collect { GrantedAuthority role -> role.authority }
]
if (useBearerToken) {
result.token_type = 'Bearer'
result.access_token = accessToken.accessToken
if (accessToken.expiration) {
result.expires_in = accessToken.expiration
}
if (accessToken.refreshToken) result.refresh_token = accessToken.refreshToken
} else {
result["$tokenPropertyName".toString()] = accessToken.accessToken
}
if (userDetails instanceof OauthUser) {
CommonProfile profile = (userDetails as OauthUser).userProfile
result.email = profile.email
result.displayName = profile.displayName
}
JSON jsonResult = ResultUtils.ok(result) as JSON
log.debug "Generated JSON:\n${jsonResult.toString(true)}"
return jsonResult.toString()
}
}
4、没有权限(403)
package middol.auth
import grails.converters.JSON
import groovy.util.logging.Slf4j
import middol.result.ResultCodeEnum
import middol.result.ResultUtils
import org.springframework.http.HttpStatus
import org.springframework.security.access.AccessDeniedException
import org.springframework.security.web.WebAttributes
import org.springframework.security.web.access.AccessDeniedHandlerImpl
import javax.servlet.RequestDispatcher
import javax.servlet.ServletException
import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpServletResponse
/**
* @Description: 没有权限
* @Author: zhangjiayu@middol.com
* @CreateDate: 2020/7/21 18:38
* @Version: 1.0
*/
@Slf4j
class MiddolTokenAccessDeniedHandler extends AccessDeniedHandlerImpl {
@Override
void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
response.addHeader('WWW-Authenticate', 'Bearer error="insufficient_scope"')
response.setContentType("application/json;charset=utf-8")
log.debug("没有权限:${accessDeniedException.message}")
// super.handle(request, response, accessDeniedException)
response.setStatus(HttpStatus.FORBIDDEN.value())
ResultCodeEnum rce = ResultCodeEnum.NO_AUTH
log.debug("设置返回结果:${rce.getMsg()}")
response << (ResultUtils.error(rce.getCode(), accessDeniedException.message) as JSON)
}
}
conf/spring/resources.groovy 配置
bean{
def conf = SpringSecurityUtils.securityConfig
restAuthenticationSuccessHandler(MiddolAuthenticationSuccessHandler) {
renderer = ref('accessTokenJsonRenderer')
}
restAuthenticationFailureHandler(MiddolAuthenticationFailureHandler) {
statusCode = conf.rest.login.failureStatusCode?: HttpServletResponse.SC_UNAUTHORIZED
}
restAccessDeniedHandler(MiddolTokenAccessDeniedHandler) {
errorPage = null //403
}
accessTokenJsonRenderer(MiddolAccessTokenJsonRenderer){
usernamePropertyName = conf.rest.token.rendering.usernamePropertyName
tokenPropertyName = conf.rest.token.rendering.tokenPropertyName
authoritiesPropertyName = conf.rest.token.rendering.authoritiesPropertyName
useBearerToken = conf.rest.token.validation.useBearerToken
}
}