当前位置: 首页 > 工具软件 > Grails-OAuth > 使用案例 >

Grails Security Rest plugin 统一返回格式

雍飞雨
2023-12-01

登录成功(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
    }
}

ResultUtils工具

 

 类似资料: