> 文档中心 > 【权限管理平台】Day—03登录功能实现以及权限分配

【权限管理平台】Day—03登录功能实现以及权限分配


【权限管理平台】项目开发Day—03

🏡  博客首页:派 大 星

⛳️  欢迎关注  ❤️ 点赞  🎒 收藏  ✏️ 留言

🎢  本文由派大星原创编撰

🚧  系列专栏:项目从0搭建

🎈  本系列项目从设计到实现源码全部开源免费学习使用,一起追向理想,欢迎各位大佬监督打卡开发!


在这里插入图片描述


目录

    • 【权限管理平台】项目开发Day—03
      • 🍉 难度分析
      • 🍒 技术介绍
      • 🍑 集成验证码
      • 🍇 登录功能集成

🍉 难度分析

​       说起登录功能的实现可以实现的相当简单,简单到只需要让用户输入用户名密码就可以完成登录操作,但是网站的安全性无法得到保证 ❌;当然也可以实现的相当麻烦,加上各种外部校验,例如:验证码选字加减乘除,这样既可以美化我们的登录功能,同时又可以提高网站的安全性  ✅

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zbt7owMx-1651561860125)(/Users/wumao/Documents/Typora笔记/typora-user-images/image-20220503132015322.png)]

🍒 技术介绍

​       本项目的登录功能我采用的是后面比较复杂的实现方式,由于用户在登录后,需要将该用户所携带的权限以及角色信息与用户紧贴,所以,这部分我采用的是将用户信息以及权限信息放入jwt中的荷载(Payload 中,通过Shiro自带的Realm中的授权机制进行用户与权限间的紧贴实现。同时也给登录功能添加了输入项——验证码,数据库对密码进行MD5二次加密入库处理,对平台的安全性进一步的提高。

🍑 集成验证码

引入依赖

<dependency>  <groupId>com.github.axet</groupId>  <artifactId>kaptcha</artifactId>  <version>0.0.9</version></dependency>

​       在集成验证码功能时需要配置关于它的属性,例如:生成的验证码是否有边框、边框的颜色、字体的颜色、大小等等属性!该配置类必须需要,不然启动项目会报错 ❌

验证码配置

@Configurationpublic class CaptchaConfig {    @Bean    public DefaultKaptcha getDefaultKaptcha(){ //验证码生成器 DefaultKaptcha defaultKaptcha=new DefaultKaptcha(); //配置 Properties properties = new Properties(); //是否有边框 properties.setProperty("kaptcha.border", "yes"); //设置边框颜色 properties.setProperty("kaptcha.border.color", "105,179,90"); //边框粗细度,默认为1 // properties.setProperty("kaptcha.border.thickness","1"); //验证码 properties.setProperty("kaptcha.session.key","code"); //验证码文本字符颜色 默认为黑色 properties.setProperty("kaptcha.textproducer.font.color", "blue"); //设置字体样式 properties.setProperty("kaptcha.textproducer.font.names", "宋体,楷体,微软雅黑"); //字体大小,默认40 properties.setProperty("kaptcha.textproducer.font.size", "30"); //验证码文本字符内容范围 默认为abced2345678gfynmnpwx // properties.setProperty("kaptcha.textproducer.char.string", ""); //字符长度,默认为5 properties.setProperty("kaptcha.textproducer.char.length", "4"); //字符间距 默认为2 properties.setProperty("kaptcha.textproducer.char.space", "4"); //验证码图片宽度 默认为200 properties.setProperty("kaptcha.image.width", "100"); //验证码图片高度 默认为40 properties.setProperty("kaptcha.image.height", "40"); Config config = new Config(properties); defaultKaptcha.setConfig(config); return defaultKaptcha;    }}

​       但是生成的验证码我们又该如何去获取呢?两种方案:第一种存入Session中,在业务逻辑中采用request.getSession.setAttribute()/request.getSession.getAttribute()先存后取,当我们取出来之后可以调用 removeAttribute()对存入的验证码进行删除操作;第二种是将生成的验证码存储到Redis中的,在业逻辑中使用set()/get()方法对存入的验证码进行存取,但是使用Redis的好处是在存储的同时可以对指定的key设置过期时间,这样就可以不用再调用API进行删除操作。

生成验证码

    @Autowired    private DefaultKaptcha defaultKaptcha;    @Autowired    private RedisService redisService;    @ApiOperation(value = "验证码")    @GetMapping(value = "/captcha",produces = "image/jepg")    public void captcha(HttpServletRequest request, HttpServletResponse response) throws Exception{ // 定义response输出类型为image/jpeg类型 response.setDateHeader("Expires", 0); // Set standard HTTP/1.1 no-cache headers. response.setHeader("Cache-Control", "no-store, no-cache, mustrevalidate"); // Set IE extended HTTP/1.1 no-cache headers (use addHeader). response.addHeader("Cache-Control", "post-check=0, pre-check=0"); // Set standard HTTP/1.0 no-cache header. response.setHeader("Pragma", "no-cache"); // return a jpeg response.setContentType("image/jpeg"); //-------------------生成验证码 begin -------------------------- String text = defaultKaptcha.createText(); System.out.println("验证码内容:"+text); //将验证码内容放入session //request.getSession().setAttribute("captcha",text);      //将验证码放入Redis中,并设置过期时间为1分钟 redisService.set("captcha",text,60, TimeUnit.SECONDS); //根据文本验证码内容创建图形验证码 BufferedImage image = defaultKaptcha.createImage(text); ServletOutputStream outputStream = null; try {     outputStream = response.getOutputStream();     //输出流输出图片     ImageIO.write(image,"jpg",outputStream);     outputStream.flush(); } catch (IOException e) {     e.printStackTrace(); }finally {     if (outputStream != null){  outputStream.close();     } } //-------------------生成验证码 end --------------------------    }

使用Swagger进行接口测试

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rXP1ILPU-1651561860126)(/Users/wumao/Documents/Typora笔记/typora-user-images/image-20220503143606416.png)]

测试成功❗️ 使用验证码可以降低被脚本暴力破解的风险!在图中在加入些许干扰竖线,使其破解脚本不能直接读取验证码中的内容。

🍇 登录功能集成

前提:

​       在实现登录功能时,我们需要用户在前端传递的用户名、密码以及验证码信息来进行校验【数据校验需要前后端共同参与才会使网站的安全性更高】但是这些信息部分是用户表中的信息,部分又不属于,遇到这种情况,通常需要我们对需要校验的数据进行二次封装,从而达到对代码的复用以及解耦。

数据封装

@Datapublic class LoginVo {    @ApiModelProperty(value = "用户账号")    @NotBlank(message = "用户名不能为空")    private String username;    @ApiModelProperty(value = "用户密码")    @NotBlank(message = "密码不能为空")    private String password;    @ApiModelProperty(value = "验证码")    @NotBlank(message = "验证码不能为空")    private String captcha;}

​       代码中的@NotBlank(message="xxx")是一种注解式校验。比如我们判断字符串是否为空会选择在业务逻辑中使用StringUtils.isEmpty()等方法来进行判断,如果为空则抛出异常,但是如果我们需要校验的字段非常多,那么使用这种方式是完全不可取的,代码的冗余度过高。但是注解式校验的就解决了这方面的问题,使得我们的业务逻辑更简洁、易懂。❗️❗️❗️注意: 如果属性使用注解式校验的话,接口处传出对应参数对象时需要添加注解@Valid

登录功能的具体实现逻辑

    /     * 用户登录     * @param vo     * @return     */    @Override    public RespBody login(LoginVo vo) { String code = (String) redisService.get("captcha"); //判断验证码是否过期 if (!redisService.hasKey("captcha")){     throw new BusinessException(BaseResponseCode.KEY_ALREADY_EXPIRED); } //忽略字符大小写校验验证码是否正确 if (!vo.getCaptcha().equalsIgnoreCase(code)){     throw new BusinessException(BaseResponseCode.CAPTCHA_ERROR); } //判断用户是否存在 SysUser user = userMapper.getUserByName(vo.getUsername()); if (user == null){     throw new BusinessException(BaseResponseCode.ACCOUNT_ERROR); } //判断用户状态 if (user.getStatus() == 2){     throw new BusinessException(BaseResponseCode.ACCOUNT_LOCKED); } //校验密码 if (!PasswordUtils.matches(user.getSalt(),vo.getPassword(),user.getPassword())){     throw new BusinessException(BaseResponseCode.ACCOUNT_PASSWORD_ERROR); } RespBody body = new RespBody(); body.setId(user.getId()); body.setUsername(user.getUsername()); Map<String,Object> claims = new HashMap<>();      //将用户角色/权限信息添加到荷载中 claims.put(Constant.ROLES_INFOS_KEY,getRoleByUserId(user.getId())); claims.put(Constant.PERMISSIONS_INFOS_KEY,getPermissionByUserId(user.getId())); claims.put(Constant.JWT_USER_NAME,user.getUsername()); String accessToken = JwtTokenUtil.getAccessToken(user.getId(), claims); body.setAccessToken(accessToken); return body;    }

测试接口

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZqrT7tPd-1651561860126)(/Users/wumao/Documents/Typora笔记/typora-user-images/image-20220503150726923.png)]

测试成功❗️❗️

今天的内容到这里就结束了,希望可以帮助到各位路过的小伙伴!

新鲜出炉的代码将会及时更新到Gitee仓库

以上代码属于部分实现,想要了解全部配置请移步 派大星的Gitee仓库

今天的工作就进行到这里!希望大佬们可以监督派大星一步步从0搭建该平台!
在这里插入图片描述