视焦点讯!只要三个注解,优雅的实现微服务鉴权!
前面的文章中介绍了网关集成Spring Security实现网关层面的统一的认证鉴权。
鉴权放在各个微服务中如何做?feign的调用如何做到的鉴权?今天针对以上两个问题深入聊聊如何通过三个注解解决。
(资料图片)
前面的几篇文章陈某都是将鉴权和认证统一的放在了网关层面,架构如下:
微服务中的鉴权还有另外一种思路:将鉴权交给下游的各个微服务,网关层面只做路由转发。
这种思路其实实现起来也是很简单,下面针对网关层面鉴权的代码改造一下即可完成:实战干货!Spring Cloud Gateway 整合 OAuth2.0 实现分布式统一认证授权!
1. 干掉鉴权管理器在网关统一鉴权实际是依赖的鉴权管理器ReactiveAuthorizationManager,所有的请求都需要经过鉴权管理器的去对登录用户的权限进行鉴权。
这个鉴权管理器在网关鉴权的文章中也有介绍,在陈某的《Spring Cloud Alibaba 实战》中配置拦截也很简单,如下:
除了配置的白名单,其他的请求一律都要被网关的鉴权管理器拦截鉴权,只有鉴权通过才能放行路由转发给下游服务。
看到这里思路是不是很清楚了,想要将鉴权交给下游服务,只需要在网关层面直接放行,不走鉴权管理器,代码如下:
http .... //白名单直接放行 .pathMatchers(ArrayUtil.toArray(whiteUrls.getUrls(), String.class)).permitAll() //其他的任何请求直接放行 .anyExchange().permitAll() .....2. 定义三个注解
经过第①步,鉴权已经下放给下游服务了,那么下游服务如何进行拦截鉴权呢?
其实Spring Security 提供了3个注解用于控制权限,如下:
@Secured@PreAuthorize@PostAuthorize关于这三个注解就不再详细介绍了,有兴趣的可以去查阅官方文档。
陈某这里并不打算使用的内置的三个注解实现,而是自定义了三个注解,如下:
1).@RequiresLogin见名知意,只有用户登录才能放行,代码如下:
/** * @author 公众号:码猿技术专栏 * @url: www.java-family.cn * @description 登录认证的注解,标注在controller方法上,一定要是登录才能的访问的接口 */@Retention(RetentionPolicy.RUNTIME)@Target({ElementType.METHOD, ElementType.TYPE})public @interface RequiresLogin {}2).@RequiresPermissions
见名知意,只有拥有指定权限才能放行,代码如下:
/** * @author 公众号:码猿技术专栏 * @url: www.java-family.cn * @description 标注在controller方法上,确保拥有指定权限才能访问该接口 */@Retention(RetentionPolicy.RUNTIME)@Target({ElementType.METHOD, ElementType.TYPE})public @interface RequiresPermissions { /** * 需要校验的权限码 */ String[] value() default {}; /** * 验证模式:AND | OR,默认AND */ Logical logical() default Logical.AND;}
3).@RequiresRoles
见名知意,只有拥有指定角色才能放行,代码如下:
/** * @author 公众号:码猿技术专栏 * @url: www.java-family.cn * @description 标注在controller方法上,确保拥有指定的角色才能访问该接口 */@Retention(RetentionPolicy.RUNTIME)@Target({ElementType.METHOD, ElementType.TYPE})public @interface RequiresRoles { /** * 需要校验的角色标识,默认超管和管理员 */ String[] value() default {OAuthConstant.ROLE_ROOT_CODE,OAuthConstant.ROLE_ADMIN_CODE}; /** * 验证逻辑:AND | OR,默认AND */ Logical logical() default Logical.AND;}
以上三个注解的含义想必都很好理解,这里就不再解释了....
3. 注解切面定义注解有了,那么如何去拦截呢?这里陈某定义了一个切面进行拦截,关键代码如下:
/** * @author 公众号:码猿技术专栏 * @url: www.java-family.cn * @description @RequiresLogin,@RequiresPermissions,@RequiresRoles 注解的切面 */@Aspect@Componentpublic class PreAuthorizeAspect { /** * 构建 */ public PreAuthorizeAspect() { } /** * 定义AOP签名 (切入所有使用鉴权注解的方法) */ public static final String POINTCUT_SIGN = " @annotation(com.mugu.blog.common.annotation.RequiresLogin) || " + "@annotation(com.mugu.blog.common.annotation.RequiresPermissions) || " + "@annotation(com.mugu.blog.common.annotation.RequiresRoles)"; /** * 声明AOP签名 */ @Pointcut(POINTCUT_SIGN) public void pointcut() { } /** * 环绕切入 * * @param joinPoint 切面对象 * @return 底层方法执行后的返回值 * @throws Throwable 底层方法抛出的异常 */ @Around("pointcut()") public Object around(ProceedingJoinPoint joinPoint) throws Throwable { // 注解鉴权 MethodSignature signature = (MethodSignature) joinPoint.getSignature(); checkMethodAnnotation(signature.getMethod()); try { // 执行原有逻辑 Object obj = joinPoint.proceed(); return obj; } catch (Throwable e) { throw e; } } /** * 对一个Method对象进行注解检查 */ public void checkMethodAnnotation(Method method) { // 校验 @RequiresLogin 注解 RequiresLogin requiresLogin = method.getAnnotation(RequiresLogin.class); if (requiresLogin != null) { doCheckLogin(); } // 校验 @RequiresRoles 注解 RequiresRoles requiresRoles = method.getAnnotation(RequiresRoles.class); if (requiresRoles != null) { doCheckRole(requiresRoles); } // 校验 @RequiresPermissions 注解 RequiresPermissions requiresPermissions = method.getAnnotation(RequiresPermissions.class); if (requiresPermissions != null) { doCheckPermissions(requiresPermissions); } } /** * 校验有无登录 */ private void doCheckLogin() { LoginVal loginVal = SecurityContextHolder.get(); if (Objects.isNull(loginVal)) throw new ServiceException(ResultCode.INVALID_TOKEN.getCode(), ResultCode.INVALID_TOKEN.getMsg()); } /** * 校验有无对应的角色 */ private void doCheckRole(RequiresRoles requiresRoles){ String[] roles = requiresRoles.value(); LoginVal loginVal = OauthUtils.getCurrentUser(); //该登录用户对应的角色 String[] authorities = loginVal.getAuthorities(); boolean match=false; //and 逻辑 if (requiresRoles.logical()==Logical.AND){ match = Arrays.stream(authorities).filter(StrUtil::isNotBlank).allMatch(item -> CollectionUtil.contains(Arrays.asList(roles), item)); }else{ //OR 逻辑 match = Arrays.stream(authorities).filter(StrUtil::isNotBlank).anyMatch(item -> CollectionUtil.contains(Arrays.asList(roles), item)); } if (!match) throw new ServiceException(ResultCode.NO_PERMISSION.getCode(), ResultCode.NO_PERMISSION.getMsg()); } /** * TODO 自己实现,由于并未集成前端的菜单权限,根据业务需求自己实现 */ private void doCheckPermissions(RequiresPermissions requiresPermissions){ }}
其实这中间的逻辑非常简单,就是解析的Token中的权限、角色然后和注解中的指定的进行比对。
@RequiresPermissions这个注解的逻辑陈某并未实现,自己根据业务模仿着完成,算是一道思考题了....
4. 注解使用比如《Spring Cloud Alibaba 实战》项目中有一个添加文章的接口,只有超管和管理员的角色才能添加,那么可以使用@RequiresRoles注解进行标注,如下:
@RequiresRoles@AvoidRepeatableCommit@ApiOperation("添加文章")@PostMapping("/add")public ResultMsgadd(@RequestBody @Valid ArticleAddReq req){ .......}
效果这里就不演示了,实际的效果:非超管和管理员角色用户登录访问,将会直接被拦截,返回无权限。
注意:这里仅仅解决了下游服务鉴权的问题,那么feign调用是否也适用?
当然适用,这里使用的是切面方式,feign内部其实使用的是http方式调用,对于接口来说一样适用。
比如《Spring Cloud Alibaba 实战》项目中获取文章列表的接口,其中会通过feign的方式调用评论服务中的接口获取文章评论总数,这里一旦加上了@RequiresRoles,那么调用将会失败,代码如下:
@RequiresRoles@ApiOperation(value = "批量获取文章总数")@PostMapping(value = "/list/total")public ResultMsg总结> listTotal(@RequestBody @Valid List
param){....}
本文主要介绍了微服务中如何将鉴权下放到微服务中,也是为了解决读者的疑惑,实际生产中除非业务需要,陈某还是建议将鉴权统一放到网关中。
标签:
相关文章
视焦点讯!只要三个注解,优雅的实现微服务鉴权!
前面的文章中介绍了网关集成SpringSecurity实现网关层面的统一的认证鉴权。鉴权放在各个微服务中如何做?feign的调用如何做到的鉴权?今天针对以上两
矩阵股份4月17日快速上涨
以下是矩阵股份在北京时间4月17日09:42分盘口异动快照:4月17日,矩阵股份盘中快速上涨,5分钟内涨幅超过2%,截至9点42分,报28 57元,成交143
奇骏混动版实车曝光,上海车展正式亮相,还能逆袭吗?_当前看点
从实车来看,混动版车型的外观整体造型和燃油版相比没有太大的变化,包括前脸部分的造型没有明显的调整。尾部的整体造型也没有明显的变化,主
天天快播:青岛今天白天多云间晴 夜间局部有阵雨或雷雨 最高气温17℃ 最低气温13℃
青岛市气象台17日06时发布:【青岛市区】今天白天,多云间晴,东南风4到5级阵风7到8级,今天夜间,多云转阴,局部有阵雨或雷雨,有轻雾,东南
2023年4月16日上海市邻苯二甲酸酐价格最新行情预测-全球快播
据中国报告大厅对2023年4月16日上海市邻苯二甲酸酐价格最新走势监测显示:2023年4月16日上海市邻苯二甲酸酐(含量
环球热推荐:苹果设备又出Bug!客服回应:并非钓鱼链接
近日,苹果在线服务频频出现故障。4月16日,多位用户反映,在没有下载软件、需要支付的情况下,苹果设备在短时间内多次要求用
阿姨爷叔请提问|肿瘤筛查做CT,辐射有多大?_世界关注
01:56前两天,市卫健委发布了上海最新癌症监测数据,上海全市新发癌症病例9 14万例,发病率为623 10万,发病前三
热头条丨十二烷基醚硫酸钠 AES商品报价动态(2023-04-16)
交易商品牌 产地交货地最新报价AES 70%含量工业级东营市鑫浩化工有限公司南京山东省7300元 吨济南星达特生物科技有限公司南京山东省7300元 吨
饭后 喉咙堵_饭后喉咙堵是食道癌吗-当前关注
1、如果进食时有呛咳感、进食不畅或胸骨后不适,要注意食管癌、胃食管反流病、良性食管狭窄和贲门失弛缓症。2、如果是进食后咽
2023年虫害防治行业股票有哪些?(4月16日):当前消息
2023年虫害防治行业股票有哪些?(4月16日),以下是南方财富网为您整理的2023年虫害防治概念股:中农立华:农药原药供应链服务龙头,打造“一
2023年武汉马拉松半马男子冠军出炉|焦点要闻
极目新闻记者夏雨2023年武汉马拉松半马男子冠军出炉!曹欢,95年,湖北大冶人。自由职业者,第四次参加汉马,参加过五六
有规范才有好未来 全球新消息
有规范才有好未来---近日,国家互联网信息办公室就《生成式人工智能服务管理办法(征求意见稿)》公开征求意见,引起业界关注。生成式人工智能
六阿哥弘曕(爱新觉罗弘曕)
六阿哥弘曕,爱新觉罗弘曕这个很多人还不知道,现在让我们一起来看看吧!1、雍正有十个儿子,其中活到成年的有弘时、弘历、弘昼、弘曕。2、1.
倪光南院士:牢牢把握中国集成电路产业发展的主动权:天天速看
4月15日,由中国电子信息行业联合会、武汉市人民政府和湖北省经济和信息化厅联合主办的“中国软件创新发展大会”在武汉举行。中国工程院院...
当前动态:祥明智能:公司董事长张敏先生参与科技研发的相关组织策划活动,近年不参与发明专利创造
祥明智能30122604月15日在投资者关系平台上答复了投资者关心的问题投资者你好根据即将施行的GBT96512022单相异步电动机试验方法的国标要求请问
全球今亮点!第15届贵州茶产业博览会开幕 以茶会友共话茶事
(记者石小杰)15日,以“干净黔茶全球共享”为主题的第15届贵州茶产业博览会(以下简称为“茶博会”)在遵义市湄潭县开幕。”贵州省人民政府副...
36.74米!白鹤滩水电站大坝取出世界最长常态混凝土芯样
记者4月14日从三峡集团了解到,白鹤滩水电站大坝日前成功取出一根长度为36 74米的混凝土岩芯,这是常态混凝土世界最长芯样。“这是继白鹤滩水
dnf符咒物品是什么_dnf符咒怎么获得
1、45级开始可以接到遗迹的系列主线任务完成头几个对话任务后就可以用10灵魂在莎兰那换到第一个宁神符咒往后可以继续在
【聚看点】青年作家杨知寒谈写作:直面人性过程中和生活互谅
顶端新闻记者黄亚芳4月15日,2023当代文学论坛暨颁奖盛典在河南郑州举行,来自全国各地的名家新锐齐聚一堂,用精品力作呈现新时代文学之美。青
用实力演绎魅力·金伯利钻石携近10亿珠宝第三次亮相消博会
4月11日至15日,由商务部、海南省人民政府主办的第三届中国国际消费品博览会在海南海口举行。本届消博会主题为共享开放机遇,共创美好生活
杭州女童遗留电梯坠亡案将开庭,其父:保姆入职一周月薪8千_观速讯
女童被遗留在电梯后哭喊阿姨。截屏图4月14日,封面新闻记者从家属处获悉,杭州女童被保姆遗留电梯坠亡案将于18日在杭州开庭。2022年6月14日
山东江苏等地将有强对流天气 新疆多雨雪天气 环球时快讯
中新网4月15日电据中央气象台网站消息,预计4月15日08时至16日08时,山东中南部、安徽北部、江苏中北部等地的部分地区将有8-10级雷暴大风或冰
世界热推荐:电视一般离地面多高_电视离地面高度要多少
1、电视机放置的高低和观看者的眼睛高度有关系的,如果观看者坐在观看位置时其眼睛距离地面的高度是1米的话,那么电视机屏幕中
资讯推荐:玛鲁_关于玛鲁介绍
玛鲁,关于玛鲁介绍这个很多人还不知道,我们一起来看看!1、玛鲁是动画片《饮茶之功夫学园》中的角色,娇巧可爱。2、在家乡老是被欺侮,所以想
全球快看点丨黄晓明不演玫瑰之战_玫瑰之战 2022年黄晓明、袁泉主演的电视剧
1、《玫瑰之战》是由一佐一佑影视江苏有限公司、新丽电视文化投资有限公司共同出品,孙皓执导,郑仁湘、张涵编剧,袁泉、黄晓明
信测标准:4月14日召开业绩说明会,投资者参与
2023年4月14日信测标准300938发布公告称公司于2023年4月14日召开业绩说明会具体内容如下问公司2022年经营情况怎么样答2022年度公司紧密围绕宏
微信上线重磅新功能?腾讯"惊动"工信部,内部已追责处罚,发生了什么?|世界快消息
来源:券商中国作者:胡飞军成为国民级产品后,腾讯的微信与QQ的异常情况举国关注。4月14日,工信部官网公告,工信部信息通信管理局听取腾讯公