Shiro缓存的使用、密码加密、Kaptcha验证码

一.缓存的使用

在shiro使用缓存有三种方式:自定义的缓存(如redis),EhCacheManager,MemoryConstrainedCacheManager

自定义缓存需要自己编写类去实现CacheManager和Cache接口,后二者shiro则已经实现

它们需要在配置文件里添加对应的bean,在然后在securityManager注册即可使用

 1      /**
 2      *这个缓存要XML配置文件,比较重
 3      */
 4     @Bean
 5     public EhCacheManager ehCacheManager() {
 6         EhCacheManager cacheManager = new EhCacheManager();
 7 //        cacheManager.setCacheManagerConfigFile("");
 8         return cacheManager;
 9     }
10 
11     /**
12      *shiro自带的 提供内存级的缓存
13      */
14     @Bean
15     public MemoryConstrainedCacheManager memoryConstrainedCacheManager(){
16         MemoryConstrainedCacheManager memoryConstrainedCacheManager=new MemoryConstrainedCacheManager();
17         return memoryConstrainedCacheManager;
18     }
19 
20    @Bean
21     public SecurityManager securityManager(UserRealm userRealm) {
22         logger.info("注入Shiro的Web过滤器-->securityManager", ShiroFilterFactoryBean.class);
23         DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
24    
25         securityManager.setRealm(userRealm);
26         //注入缓存管理器;
27         //更新权限信息后,记得在service里清除缓存
28         securityManager.setCacheManager(memoryConstrainedCacheManager());//这个如果执行多次,也是同样的一个对象;
29         return securityManager;
30     }

然后我们要在Realm类里提供清除缓存的方法

缓存在用户logout和非正常logout后都会清除,但是login状态下修改了权限就要我们在service里手动清除缓存

1     /**
2      * 清除缓存
3      */
4     public void clearCached(){
5         PrincipalCollection principals = SecurityUtils.getSubject().getPrincipals();
6         super.clearCache(principals);
7     }

 

 

二.密码加密

在配置文件里配置一个bean,用于给输入的密码使用MD5方式加密,加密1024次:

 1     /**
 2      * MD5加密配置
 3      */
 4     @Bean
 5     public HashedCredentialsMatcher hashedCredentialsMatcher(){
 6         HashedCredentialsMatcher hashedCredentialsMatcher=new HashedCredentialsMatcher();
 7         hashedCredentialsMatcher.setHashAlgorithmName("MD5");
 8         //加密次数
 9         hashedCredentialsMatcher.setHashIterations(1024);
10         return hashedCredentialsMatcher;
11     }

 在 securityManager里设置Realm的加密方法:

 1    @Bean
 2     public SecurityManager securityManager(UserRealm userRealm) {
 3         logger.info("注入Shiro的Web过滤器-->securityManager", ShiroFilterFactoryBean.class);
 4         DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
 5         //设置密码加密方法
 6         userRealm.setCredentialsMatcher(hashedCredentialsMatcher());
 7         securityManager.setRealm(userRealm);
 8         //注入缓存管理器;
 9         //更新权限信息后,记得在service里清除缓存
10         securityManager.setCacheManager(memoryConstrainedCacheManager());//这个如果执行多次,也是同样的一个对象;
11         return securityManager;
12     }

 

 

用户登录时会把账号密码装在Token里传入doGetAuthenticationInfo()方法验证,我们改一下其中的校验

 1    /**
 2      * 登录认证
 3      */
 4     @Override
 5     protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
 6         //UsernamePasswordToken对象用来存放提交的登录信息
 7         UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
 8         //查出是否有此用户
 9         User user = userService.findUserByName(token.getUsername());
10         if (user != null) {
11             //盐 一般是用户名
12             ByteSource credentialsSalt = ByteSource.Util.bytes(user.getNickname());
13             // 若存在,将此用户存放到登录认证info中,无需自己做密码对比,Shiro会为我们进行密码对比校验
14             return new SimpleAuthenticationInfo(user.getNickname(), user.getPswd(),credentialsSalt ,getName());
15         }
16         return null;
17     }

 主要是在校验中加了盐,这个盐在这我使用的是用户名,可以改。使用盐的目的是使MD5加密的结果不容易逆向破解。

 

最后我们把数据库里的明文密码改成加密后的:

1     public void passwordGen(){
2         String hashAlgorithmName = "MD5";
3         String credentials = "123456";
4         int hashIterations = 1024;
5         ByteSource credentialsSalt = ByteSource.Util.bytes("admin");
6         Object obj = new SimpleHash(hashAlgorithmName, credentials, credentialsSalt, hashIterations);
7         System.out.println(obj);
8     }

 

三 .Kaptcha验证码

maven引包

1      <!-- 验证码 -->
2         <dependency>
3             <groupId>com.github.penggle</groupId>
4             <artifactId>kaptcha</artifactId>
5             <version>2.3.2</version>
6         </dependency>        

 

新建配置类

 1 package com.tqh.demo.config;
 2 
 3 import com.google.code.kaptcha.impl.DefaultKaptcha;
 4 import org.springframework.context.annotation.Bean;
 5 import org.springframework.context.annotation.Configuration;
 6 import org.springframework.stereotype.Component;
 7 
 8 import java.util.Properties;
 9 import com.google.code.kaptcha.util.Config;
10 /**
11  * @Author: Mcorleon
12  * @Date: 18-7-31 17:04
13  */
14 @Configuration
15 public class KaptchaConfig {
16     @Bean
17     public DefaultKaptcha getDefaultKaptcha(){
18         com.google.code.kaptcha.impl.DefaultKaptcha defaultKaptcha = new com.google.code.kaptcha.impl.DefaultKaptcha();
19         Properties properties = new Properties();
20         properties.setProperty("kaptcha.border", "no");
21         properties.setProperty("kaptcha.border.color", "105,179,90");
22         properties.setProperty("kaptcha.textproducer.font.color", "red");
23         properties.setProperty("kaptcha.image.width", "100");
24         properties.setProperty("kaptcha.image.height", "40");
25         properties.setProperty("kaptcha.textproducer.font.size", "35");
26         properties.setProperty("kaptcha.background.clear.from", "white");
27         properties.setProperty("kaptcha.background.clear.to", "white");
28         properties.setProperty("kaptcha.session.key", "code");
29         properties.setProperty("kaptcha.textproducer.char.length", "4");
30         properties.setProperty("kaptcha.textproducer.font.names", "微软雅黑");
31         Config config = new Config(properties);
32         defaultKaptcha.setConfig(config);
33 
34         return defaultKaptcha;
35     }
36 }
37 //        kaptcha.border 图片边框,合法值:yes , no yes
38 //        kaptcha.border.color 边框颜色,合法值: r,g,b (and optional alpha) 或者 white,black,blue. black
39 //        kaptcha.border.thickness 边框厚度,合法值:>0 1
40 //        kaptcha.image.width 图片宽 200
41 //        kaptcha.image.height 图片高 50
42 //        kaptcha.producer.impl 图片实现类 com.google.code.kaptcha.impl.DefaultKaptcha
43 //        kaptcha.textproducer.impl 文本实现类 com.google.code.kaptcha.text.impl.DefaultTextCreator
44 //        kaptcha.textproducer.char.string 文本集合,验证码值从此集合中获取 abcde2345678gfynmnpwx
45 //        kaptcha.textproducer.char.length 验证码长度 5
46 //        kaptcha.textproducer.font.names 字体 Arial, Courier
47 //        kaptcha.textproducer.font.size 字体大小 40px.
48 //        kaptcha.textproducer.font.color 字体颜色,合法值: r,g,b 或者 white,black,blue. black
49 //        kaptcha.textproducer.char.space 文字间隔 2
50 //        kaptcha.noise.impl 干扰实现类 com.google.code.kaptcha.impl.DefaultNoise
51 //        kaptcha.noise.color 干扰颜色,合法值: r,g,b 或者 white,black,blue. black
52 //        kaptcha.obscurificator.impl 图片样式: 水纹com.google.code.kaptcha.impl.WaterRipple 鱼眼com.google.code.kaptcha.impl.FishEyeGimpy 阴影com.google.code.kaptcha.impl.ShadowGimpy com.google.code.kaptcha.impl.WaterRipple
53 //        kaptcha.background.impl 背景实现类 com.google.code.kaptcha.impl.DefaultBackground
54 //        kaptcha.background.clear.from 背景颜色渐变,开始颜色 light grey
55 //        kaptcha.background.clear.to 背景颜色渐变,结束颜色 white
56 //        kaptcha.word.impl 文字渲染器 com.google.code.kaptcha.text.impl.DefaultWordRenderer
57 //        kaptcha.session.key session key KAPTCHA_SESSION_KEY
58 //        kaptcha.session.date session date KAPTCHA_SESSION_DATE

 

控制器里新建一个用于产生验证码图片的URI

 1    @Autowired
 2     private DefaultKaptcha defaultKaptcha;
 3 
 4     @RequestMapping ("/defaultKaptcha")
 5     public void defaultKaptcha(HttpServletRequest httpServletRequest,HttpServletResponse httpServletResponse) throws Exception {
 6         byte[] captchaChallengeAsJpeg;
 7         ByteArrayOutputStream jpegOutputStream = new ByteArrayOutputStream();
 8         try {
 9             //生产验证码字符串并保存到session中
10             String createText = defaultKaptcha.createText();
11             httpServletRequest.getSession().setAttribute("vrifyCode", createText);
12             //使用生产的验证码字符串返回一个BufferedImage对象并转为byte写入到byte数组中
13             BufferedImage challenge = defaultKaptcha.createImage(createText);
14             ImageIO.write(challenge, "jpg", jpegOutputStream);
15         } catch (IllegalArgumentException e) {
16             httpServletResponse.sendError(HttpServletResponse.SC_NOT_FOUND);
17             return;
18         }
19 
20         //定义response输出类型为image/jpeg类型,使用response输出流输出图片的byte数组
21         captchaChallengeAsJpeg = jpegOutputStream.toByteArray();
22         httpServletResponse.setHeader("Cache-Control", "no-store");
23         httpServletResponse.setHeader("Pragma", "no-cache");
24         httpServletResponse.setDateHeader("Expires", 0);
25         httpServletResponse.setContentType("image/jpeg");
26         ServletOutputStream responseOutputStream =
27                 httpServletResponse.getOutputStream();
28         responseOutputStream.write(captchaChallengeAsJpeg);
29         responseOutputStream.flush();
30         responseOutputStream.close();
31     }

 注意:要在shiro配置类中设置过滤链不拦截 /defaultKaptcha

验证码html: <input type="text" name="vrifyCode" /> <img alt="验证码" onclick = "this.src='/defaultKaptcha?d='+new Date()*1" src="/defaultKaptcha" />

点击可更换

在login的控制器中从session取验证码与输入的比对即可

posted @ 2018-07-31 16:19  mcorleon  阅读(773)  评论(0编辑  收藏  举报