范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文

给女朋友讲某宝是如何设计用户权限管理的(一)

  一、概述
  java应用系统设计过程中,用户认证、用户授权、鉴权是绕不过去的话题。
  如果这个权限管理的设计,没有做到与业务系统的隔离,拓展性不够强,很容易就会拖后腿。
  这个问题应该做过开发的同学都会有所体会。
  现在网络上的各种关于权限管理的框架比较主流的有 Apache Shiro,Spring Security,Sa-Token(新兴起的一个优秀框架)。
  这里会有同学说,既然已经有这么多的成熟优秀的权限管理框架,为什么还有再给大家介绍这种实现思路。
  在本人工作和学习的过程中,经常会使用这些优秀的权限管理框架。
  但是,一旦是这些三方框架出现的异常和问题,想要排查,就比较麻烦。要么就是靠着百度大家的经验。要么就是猛扒代码,一点点去排查。
  三方框架对于我们使用者来说,就像是一个黑盒。这一点一直让我觉得有点不顺畅。
  同学们,谁不想要一个自己知根知底的的权限管理框架呢。
  喜欢的朋友可以关注一下
  二、框架使用体验
  2.1 项目初始化配置
  Springboot老三样。添加pom依赖修改配置文件编写组件代码
  引入pom依赖:    com.lhit.security   security-client   0.0.1-SNAPSHOT      com.lhit.security   security-server   0.0.1-SNAPSHOT 
  修改配置文件:lhit:   security:     server-url-of-check-url: /security/check_url                          # 不配置默认就是这个路径     server-url-of-check-perms-code: /security/check_perms_code            # 不配置默认就是这个路径     server-url-of-check-static-res-path: /security/check_static_res_path  # 不配置默认就是这个路径     server-url-of-token-to-authority: /security/token_to_authority        # 不配置默认就是这个路径     useCloud: false                                                        # 不配置默认为true回去注册中心查找授权中心服务     token-key: LHTOKEN                                                    # 请求头中token的key     expire: 9999999
  2.2 用户登录
  自定义一个凭证类@Getter @Setter @NoArgsConstructor @AllArgsConstructor public class UsernamePasswordVerification implements SecurityVoucher {       // 用户名     @NotBlank(message = "未上传 username")     @ApiModelProperty(value = "username")     private String username;       @NotBlank(message = "密码不能为空")     @ApiModelProperty(value = "密码")     private String password; }
  自定义一个凭证类认证器:
  这个认证器很简单 就是默认admin 密码 123456 然后给与了固定的角色和全部的资源。实际应用中应该从数据库中获取到用户的权限 并组织返回的securityAuthority。@Component public class DefaultUsernamePasswordVoucherVoucherVerification implements SecurityVoucherVerification {     @Override     public SecurityAuthority verification(UsernamePasswordVerification usernamePasswordVoucher) throws Exception {         if (usernamePasswordVoucher.getUsername().equals("admin") && usernamePasswordVoucher.getPassword().equals("123456")) {             SecurityAuthority securityAuthority = new SecurityAuthority();             securityAuthority.setSecurityUser(new SecurityUser("1", "admin"));             securityAuthority.setSecurityRoleList(Lists.newArrayList(new SecurityRole(0L,"roleNo","管理员")));             securityAuthority.setSecurityResList(Lists.newArrayList(SecurityRes.allCodeRes(), SecurityRes.allUrlRes()));             return securityAuthority;         }         throw CommonException.create(ServerResponse.createByError("用户名或密码错误,默认admin-123456"));     } }
  开放认证接口:@Slf4j @Api(tags = "认证接口") @RestController @RequestMapping("/security") public class AuthorizeController {       @Autowired     private SecurityServer securityServer;       @PostMapping("/login/username_password")     @ApiOperation("系统用户登录")     @ApiImplicitParams({             @ApiImplicitParam(paramType = "body", dataType = "UsernamePasswordVerification", dataTypeClass = UsernamePasswordVerification.class, name = "param", value = "参数")     })     public ServerResponse sysUserLoginByUsernamePassword(@Validated @RequestBody UsernamePasswordVerification param) throws Exception {         log.info("|-----------------------------------------------|");         log.info("进入 系统用户登录 接口 : LoginAuthenticationController-sysUserLoginByUsernamePassword ");         AuthenticationVo authorize = securityServer.authorize(param);         return ServerResponse.createBySuccess("登录成功", authorize);     }       @GetMapping("/logout")     @ApiOperation("用户退出")     @ApiImplicitParams({             @ApiImplicitParam(paramType = "header", dataType = "string", name = "LHTOKEN", value = "用户token"),     })     public ServerResponse logout(@RequestHeader(value = "LHTOKEN", defaultValue = "") String token) throws Exception {         log.info("|-----------------------------------------------|");         log.info("进入 获取当前用户信息 接口 : SysUserController-logout");         securityServer.tokenDestroy(new TokenParam(token));         return ServerResponse.createBySuccess("退出成功");     }       /**      * 获取当前用户信息      */     @GetMapping("/current_user_prems")     @ApiOperation("获取当前用户权限信息")     @ApiImplicitParams({             @ApiImplicitParam(paramType = "header", dataType = "string", name = "LHTOKEN", value = "用户token"),     })     @TokenToAuthority // 这个注解将请求同中的token信息转换为securityAuthority参数,到当前方法中。     public ServerResponse getUesrPremsInfo(@ApiIgnore SecurityAuthority securityAuthority) throws Exception {         log.info("|-----------------------------------------------|");         log.info("进入 获取当前用户信息 接口 : SysUserCurrentUserController-getUesrInfo");         return ServerResponse.createBySuccess("获取成功", securityAuthority);     }   }
  2.3 权限验证
  路由级别鉴权:
  不用做其他额外的配置 只需要打上@HasUrl 就会获取到Controller层的当前url地址,并校验用户是否有访问该url的权限。
  并将解析后的用户信息放到方法的SecurityAuthority参数中
  在第一步用户登录时,默认给了SecurityRes.allUrlRes() ,则配置了 /** 的url访问权限。/**  * 删除用户  */ @DeleteMapping("/delete/{userId}") @ApiOperation("删除用户") @ApiImplicitParams({         @ApiImplicitParam(paramType = "header", dataType = "string", name = "LHTOKEN", value = "用户token"),         @ApiImplicitParam(paramType = "path", dataType = "Long", dataTypeClass = Long.class, name = "userId", value = "用户id") }) @HasUrl public ServerResponse delUser(@PathVariable(value = "userId") Long userId, @ApiIgnore SecurityAuthority securityAuthority) throws Exception {     log.info("|-----------------------------------------------|");     log.info("进入 删除用户 接口 : SysUserAdminController-delUser");     sysUserService.delUser(userId, getCurrentSysUser(securityAuthority));     return ServerResponse.createBySuccess("删除成功"); }
  方法级别鉴权@Slf4j @Service("sysUserService") public class SysUserServiceImpl implements SysUserService {   /**   * 删除用户   */   @Override   @Transactional(rollbackFor = Exception.class)   @HasPermsCode(permsCode = "user:delete") // 该数据会校验springMVC上下文中token是否有访问该资源的权限   public void delUser(Long userId, SysUser sysUser) throws Exception {     log.info("开始 删除用户");     SysUser checkUser = sysUserDao.getById(userId);     if (checkUser == null) {       throw CommonException.create(ServerResponse.createByError("用户信息不存在"));     }     try {       // 删除用户       checkUser.setDelFlag(true);       checkUser.setUpdateBy(sysUser.getId());       checkUser.setUpdateTime(new Date());       sysUserDao.updateById(checkUser);       log.info("完成 删除用户");     } catch (Exception e) {       throw CommonException.create(e, ServerResponse.createByError("删除用户失败,请联系管理员"));     }   }     }
  验证用户是否登录@Slf4j @Api(tags = "认证接口") @RestController @RequestMapping("/security") public class AuthorizeController {     /**      * 获取当前用户信息      */     @GetMapping("/current_user_prems")     @ApiOperation("获取当前用户权限信息")     @ApiImplicitParams({             @ApiImplicitParam(paramType = "header", dataType = "string", name = "LHTOKEN", value = "用户token"),     })     @TokenToAuthority // 这个注解将请求同中的token信息转换为securityAuthority参数,到当前方法中。如果转换失败抛出401异常     public ServerResponse getUesrPremsInfo(@ApiIgnore SecurityAuthority securityAuthority) throws Exception {         log.info("|-----------------------------------------------|");         log.info("进入 获取当前用户信息 接口 : SysUserCurrentUserController-getUesrInfo");         return ServerResponse.createBySuccess("获取成功", securityAuthority);     }   }
  三、时间地点人物
  想要描述一个事情,都是将时间地点人物介绍完,才能吧事情描述清楚。
  介绍这个设计思路也需要介绍前提:什么时候用这个框架框架能提供哪些能力框架应该有哪些抽象组件
  3.1 什么时候用这个框架
  显然,如果系统需要提供用户认证、用户授权、用户鉴权的时候,就需要有一个权限管理的模块。
  整个流程应该是:
  用户认证 --> 颁发token(用户授权) --> 用户鉴权 --> token回收
  3.2 框架要提供哪些能力  首先可以对系统用户进行认证。可以将生成用户口令给客户端,并可以管理该口令。用户携带口令访问资源是可以判断用户是否有权限来访问这个资源。
  以上能力老生常谈就是最基础的权限管理。
  3.3 框架应该有哪些抽象组件
  这个问题是面向对象开发的java程序员必须要好好思考的问题,就是当你接到一个需求时,如何以面向对象的思维来分析和设计程序来完成需求。
  3.3.1 用户认证
  用户认证,最最常见的场景就是用户名密码登录。
  在这个场景中可能存在:
  用户名+密码、用户名+密码+验证码、手机号+验证码、邮箱+验证码 ...... 这么多的登录方式。
  而通常来验证这些登录信息是否合法,一般都是要去数据库中读取用户的注册信息来完成认证。
  这个场景下可以抽象出来的类有:
  1. 凭证类:用户名+密码、用户名+密码+验证码、手机号+验证码、邮箱+验证码 ......
  2. 凭证类验证器:用来验证用户上传的凭证是否是合法的。
  3.3.2 用户授权
  当用户完成认证凭证验证后,服务器应该返回一个用户的口令(token),给用户使用。
  并且用户的token应该可以关联并携带出用户绑定的所有资源权限,和角色、部门、岗位等等信息。
  用户的资源又分为:
  静态资源:
  菜单、按钮等静态资源
  文档、图片等静态资源
  动态资源:
  对某种资源的CURD权限:如 是否可以对 sys_user表数据进行CURD。
  这个场景下可以抽象出来的类:Token生成器 :用来生成用户token.用户权限描述类 :存放用户基本信息、用户拥有的资源权限、用户的角色信息、用 户的其他信息(例如:岗位、部门等)角色 :典型的RBAC设计,角色代表权限的集合。岗位 :从另外一种维度给用户打标签,来区分用户的权限。部门 :从另外一种维度给用户打标签,来区分用户的权限。
  其中的岗位和部门,有些权限管理框架中没有,有的或许有一个,这里不纠结这个问题,无论是部门还是岗位,其实都是提供了一种权限判断的维度,类型给用户打上一种标签。
  3.3.3 token管理
  生成用户token后,所有的token需要管理起来。可以用来统计和维护。
  所以需要将上一步获取到的用户权限描述类的信息与token建立一种映射关系。从而可以通过token获取到用户的各种信息。
  这个场景可以抽象出来的类:
  Token管理类:用来管理所有生成的token。并建立用户信息与token的关联关系。
  3.3.4 用户鉴权
  当用户通过用户认证和用户授权后,就获取到了他的token口令。
  每次用户来访问服务资源时,都需要携带token,当服务器收到请求后,需要通过token获取到用户的所有的权限信息,来判断用户是否可以访问当前资源。
  这个场景似乎没有可以抽离出来的类,而是我们要找到一种用户鉴权的方案。
  这里,根据以往的经验,基于Spring的AOP切面编程应该是对使用者最友好的方式
  所以这里总结下我们需要鉴权的类型:用户身份验证:token是否对应着一个有效的用户身份。就是用户是不是已经登录。URL基本的鉴权:对于java开发来说就是Controller层开放的接口释放可访问。方法级别鉴权:对于java开发者来说,就对应着某个类的某个方法该用户是否可以访问,这里可以参考shiro的授权码 user:delete表示是否可以删除用户。静态资源鉴权:用户是否可以访问系统中的静态资源。比如 一张图片的下载地址。
  喜欢的朋友可以关注一下
  四、小结
  上面铺垫了那么些,其实只是想让大家能跟笔者有一个相同的认知。用户认证:就是用户登录。用户授权:就是为用户颁发一个可以表达他拥有的角色和自有的口令。用户鉴权:就是判断用户有没有权限来访问当前的资源。
  先梳理下上面总结出来的类。
  凭证类、凭证类验证器、token生成器、token管理器。
  以及,基于AOP实现的用户鉴权方案。
  大致思路:
  未完待续…
  敬请关注下一篇

骁龙8首发机型低至2999元,摩托罗拉背水一战中国商报(记者赵熠如)摩托罗拉抢在小米之前拿到了高通骁龙8芯片的全球首发。令业界惊讶的是,其将新机的起售价压低至2999元。不仅如此,摩托罗拉还喊出敢于向第一阵营发起冲击的声音。业联想打败小米抢发骁龙8,新机评测喜忧参半,后续机型要注意电子发烧友网报道(文吴子鹏)近几年,每一代高通骁龙旗舰芯片的发布,小米手机都会跟着一起做一波全网宣推,然后用全球首发机型再强调一波。然而,今年小米创始人雷军虽然对骁龙8Gen1芯片非洲之王传音,推首款5G机型,售价不到2千,国内能买到吗?提到国产手机品牌,你一定知道华为小米OPPOvivo及其旗下的子品牌,但你知道国内还有另一家手机巨头传音手机吗?传音旗下共拥有TECNOitelInfinix及Spice四个手机品起售价仅2999元!骁龙8Gen1首发机型正式确定,小米12的对手来了今年12月1日,随着高通新一代旗舰处理器骁龙8Gen1的登场,国内高端手机市场迎来了新的变革,各大厂商都在预热自家的首款骁龙8Gen1机型,竞争非常激烈。其中关于骁龙8Gen1首发如何选择适合自己的耳机?应该考虑哪些方面?新手误区解析又到了年终盘点的时间,今天笔点酷玩和大家聊一聊如何选择适合自己的耳机,以及2021年有哪些耳机值得入手。这篇先写前半部分基础干货和新手误区,下一篇再写2021优秀耳机盘点,烦请收藏收入入不敷出,有个面包车想加入货拉拉,各位有什么好的建议?关于货拉拉,有段时间失业,家里没矿!我那段时间在广州跑过大半年,加入七八个月,我也来说说货拉拉,没有了解就没发言权,个中有苦有甜!我是18年八月份加入货拉拉,买的二手面包车,茂名车老年人使用智能手机必须学会的8个功能,操作简单,一看就会分享生活小妙招,共享科技新生活!大家好,欢迎来到今天的知识分享!我是你们的好朋友小俊!在前面几期中我们给老年朋友分享了如何快速学会使用智能手机的技巧分享,很多爷爷奶奶给我留言说能不小米mix4价格崩盘,上市三个月怒降一千多块,现在入手合适吗?众所周知华为有mate系列和p系列双旗舰,其实在几年前小米也是有数字系列和mix系列双旗舰。不过自从mix3扑街之后这个系列就开始一蹶不振,一度被砍。好在今年,mix系列重启,小米华为最大的竞争对手是小米吗?为什么这么说?华为最大的敌人是美国小米最大的敌人是华为。小米?敌人算不上,不管我是不是花粉,对小米公司的企业文化天然反感。阿迪达斯永远不会使用气垫技术耐克永远也不会使用boost一个伟大的企业以首批月球样品重大发现科技日报记者金凤嫦娥五号采集的首批月球样品,能为我们揭示月球的哪些奥秘?这一问题近期有了部分答案。12月13日,中国科学院紫金山天文台发布消息称,该台徐伟彪研究员及其行星化学科研团已累计亏损28亿美元的法拉第未来公布了现状和新进展记者刘泽然编辑12月7日,FaradayFuture(FF)在其位于汉福德(Hanford,CA)工厂举行线上投资者沟通交流会上,首次向外界报告了其在工厂建设公司财务量产车交付以及
换个智能台灯放音乐无线充AI语音居家随心所欲一盏好的台灯,不仅是照明工具,更是陪伴和氛围的制造者。但是,现在真的还有人会花点时间去选购台灯吗?平时逛商场看到设计得不错的台灯,会感叹这个灯真好看摆在家里逼格很高花大价钱买放在家微信可以听文字消息了3步教你开启据微信派微信公众号消息,微信关怀模式目前已支持听文字消息,开启该功能后,仅需点一下聊天中的文字消息就能听到。值得一提的是,无论是安卓手机,还是苹果手机,用户只要将微信更新到最新版本GIECCandyPodsTWS耳机体验惊艳的颜值还有不俗的声音表现蓝牙耳机这几年发展还是挺快的,才几年间就诞生出各种各样的耳机,并且价格也在不断地下探。同时在价格下调的同时,蓝牙耳机的性能也在不断地提升。这就诞生出很多价格实惠,性能优异的高性价比北京大中电器联合北京国美发放绿色节能消费券北京商报讯(记者何倩)4月13日,北京商报记者从北京大中电器北京国美联合举办的绿色节能消费节启动仪式上了解到,绿色节能消费节将贯穿于4月9月,为北京消费者提供以旧换新补贴节能补贴补3D打印人造骨骼,成为未来太空急救需要3D打印正在社会生产中发挥着越来越重要的作用。首先,3D打印可以缩短生产制造的时间,提高效率。用传统方法制造出一个模型通常需要数天,根据模型的尺寸以及复杂程度而定,而用3D打印技术谷歌回应公开俄军事战略设施细节传言未改变俄罗斯卫星图像模糊程度美国科技媒体TheVerge4月18日报道,谷歌表示公司未改变审查俄罗斯卫星图像的方法。此前媒体广泛报道称谷歌公开俄军事战略设施高分辨率图像。据报道,当地时间周一,未实名的推特账户再无A72遗憾搭载骁龙778G,GalaxyA73物有所值GalaxyA52是三星去年最好的综合中端手机。GalaxyA72紧随其后,搭载了许多有趣的功能(包括3倍光学长焦摄像头),但三星在其最重要的一个方面做出了妥协GalaxyA72搭因价格错误瑞幸咖啡暂时关闭饿了么平台上门店北京商报讯(记者赵述评张天元)4月18日,瑞幸咖啡发布道歉信。其中显示,由于饿了么后台价格配置问题,导致瑞幸椰云套餐价格短时内出现错误,门店受到大量异常订单挤压。为正常运营,瑞幸咖为何要高频次重复地做核酸检测?专家回应来源央视新闻客户端17日上午举行的上海市疫情防控工作新闻发布会上,上海中医药大学附属岳阳中西医结合医院检验实验中心主任高春芳就目前仍在进行的高频次核酸检测的原因做了说明。高春芳表示浩瀚宇宙,无奇不有,有没有可能存在魔法文明和修仙文明?在人类的幻想之中,还存在其他和人类科技文明完全不同的文明形态,比如说魔法文明和修仙文明。人类的想象力是没有极限的,在我们的想象中,任何不可能发生的事情都有可能实现。那么宇宙这么大,总结一下4月份未来10天的新品发布会,可谓手机圈的干架4月份注定不平凡,可谓是惊喜连连不断。眼看4月份只剩下十一天,在这些时间内将举行诸多新品发布会,看看有没有你期待的,本人最喜欢的vivox80系列了吧!4月19日周二1908Hin