前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >springboot接口访问权限AOP实现

springboot接口访问权限AOP实现

作者头像
用户1225216
发布2019-05-25 18:46:28
9020
发布2019-05-25 18:46:28
举报
文章被收录于专栏:扎心了老铁扎心了老铁

场景

现在有个系统,很多接口只需要登录就可以访问,但是有些接口需要授予并验证权限。如果用注解controller的方式控制接口的权限呢?

1、注解声明代码

这个注解是要装饰在controller接口上的。

按照一般权限的设计,有用户(user)-角色(role)-权限(permission)三种实体,他们之间都是多对多关系。

注解声明的时候,可以配置要验证的角色(role)或权限(menu)。所以我这里有两个变量。

代码语言:javascript
复制
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @Author: ivan
 * @Description:
 * @Date: Created in 19:58 18/5/28
 * @Modified By:
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Authentication {
    long[] role() default {};
    long[] menu() default {};

}

2、Authentication权限验证Advice

我们以验证角色为例。

第一步,先从controller参数的request cookie里拿到用户登录信息,获取userId,我这里是card。

第二步,查询用户角色数据库,获取该user拥有哪些权限。

第三部,跟@Authentication里配置的权限进行比较,校验成功返回数据,校验失败返回错误码。

使用localthread记录了权限验证处理时间,用来进行监控。

代码语言:javascript
复制
/**
 * @Author: ivan
 * @Description:
 * @Date: Created in 20:00 18/5/28
 * @Modified By:
 */
@Aspect
@Component
@Order(-10)
public class AuthenticationAspect {

    private static Logger logger = LoggerFactory.getLogger(AuthenticationAspect.class);

    @Autowired
    private AuthDao authDao;

    ThreadLocal<Long> beginTime = new ThreadLocal<Long>();

    @Pointcut("@annotation(authentication)")
    public void AuthenticationService(Authentication authentication) {
    }

    @Around("AuthenticationService(authentication)")
    public Object doAround(ProceedingJoinPoint joinPoint, Authentication authentication) throws Throwable{
        beginTime.set(System.currentTimeMillis());
        String card = null;
        List<Long> roleList = new ArrayList<>();
        for (Object arg : joinPoint.getArgs()) {
            if (arg != null && arg.getClass() == RequestFacade.class) {
                RequestFacade request = (RequestFacade) arg;
                card = CookieUtils.getCardFromCookie(request);
                if (StringUtils.isEmpty(card)) {
                    return JsonResult.buildFailResult(-1, 1000, "权限验证未通过", null);
                }
                List<Role> roles = authDao.getRolesByCard(card);
                for (Role role : roles) {
                    roleList.add(role.getId());
                }
                break;
            }
        }
        logger.info("[authentication] user={}, roles={}", card, roleList);
        long[] aims = authentication.role();
        boolean isPass = false;
        for (long aim : aims) {
            if (roleList.contains(aim)) {
                isPass = true;
            }
        }
        if (isPass) {
            logger.info("[authentication] authentication pass, cost time: {}", System.currentTimeMillis() - beginTime.get());
            return joinPoint.proceed();
        } else {
            beginTime.set(System.currentTimeMillis());
            logger.info("[authentication] authentication reject, cost time: {}", System.currentTimeMillis() - beginTime.get());
            return JsonResult.buildFailResult(-1, 1000, "权限验证未通过", null);
        }

    }


}

3、使用方法

1、Authentication直接装饰在controller接口上,参数是role={2},即用户拥有2这个角色的时候拥有访问这个接口的权限。

2、controller第一个参数要是HttpServletRequest request,不然上面从request里面拿用户信息会失败。(这个地方确实不方便)

代码语言:javascript
复制
/**
 * 审核接口
 *
 * @author ivan
 * @date 2018/08/02
 */
@Controller
@RequestMapping("/audit")
public class AuditController {
    private static final Logger LOGGER = LoggerFactory.getLogger(AuditController.class);
    @Resource
    private AuditService auditService;


    @ResponseBody
    @PostMapping(value = "/review")
    @Authentication(role = {2})
    public JsonResult review(HttpServletRequest request, @RequestBody AduitDTO aduitDTO) {
        LOGGER.info("[aduitDTO]  video service aduitDTO={}" + aduitDTO);
        UserInfo userInfo = CookieUtils.getLoginInfoFromCookie(request);
        aduitDTO.setCard(userInfo.getCard());
        int status = 0;
        aduitDTO.setAuditor(userInfo.getCard());
        JsonResult jsonResult = null;
        if (ListEnum.ZERO.toString().equals(aduitDTO.getType())) {
            if (null != aduitDTO.getStatus() && ListEnum.ONE.toString().equals(aduitDTO.getStatus())) {
                status = auditService.review(aduitDTO);
                jsonResult = JsonResult.buildSuccessResult("审核通过");
            }
            if (null != aduitDTO.getStatus() && ListEnum.TWO.toString().equals(aduitDTO.getStatus())) {
                if(StringUtils.isEmpty(aduitDTO.getReason())){
                    return JsonResult.buildFailResult(1, 102, "请添加不通过原因!", null);
                }
                aduitDTO.setAuditTime(DateUtils.parseDateToStr(new Date() ,"yyyy-MM-dd HH:mm:ss"));
                status = auditService.updateAduit(aduitDTO);
                jsonResult = JsonResult.buildSuccessResult("审核不通过");
            }
        }

        return jsonResult;
    }
}
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019-03-28 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档