zoukankan      html  css  js  c++  java
  • Shiro + redis + 登录 + 记住我 + 验证码 + 登出(mysiteforme)

    从访问开始

    http://localhost:8080

            
        @GetMapping(value = "")
        public String index() {
            LOGGER.info("这事空地址在请求路径");
            Subject s = SecurityUtils.getSubject();
            return s.isAuthenticated() ? "redirect:index" : "login";
        }

    登录以后结果就是true ,否则去登录

     

    <input name="username" placeholder="用户名">
    <input name="password" placeholder="密码" type="password">
    
    <input type="checkbox" name="rememberMe" value="true" lay-skin="primary" checked title="记住帐号?">
    <input name="code" placeholder="验证码" type="text" > <img src="${base}/genCaptcha" width="116" height="36" id="mycode">

    图片验证码

    {base} 来源于拦截器

    生产验证码

    /**
         * 获取验证码图片和文本(验证码文本会保存在HttpSession中)
         */
        @GetMapping("/genCaptcha")
        public void genCaptcha(HttpServletRequest request, HttpServletResponse response) throws IOException {
            //设置页面不缓存
            response.setHeader("Pragma", "no-cache");
            response.setHeader("Cache-Control", "no-cache");
            response.setDateHeader("Expires", 0);
            String verifyCode = VerifyCodeUtil.generateTextCode(VerifyCodeUtil.TYPE_ALL_MIXED, 4, null);
            //将验证码放到HttpSession里面
            request.getSession().setAttribute(Constants.VALIDATE_CODE, verifyCode);
            LOGGER.info("本次生成的验证码为[" + verifyCode + "],已存放到HttpSession中");
            //设置输出的内容的类型为JPEG图像
            response.setContentType("image/jpeg");
            BufferedImage bufferedImage = VerifyCodeUtil.generateImageCode(verifyCode, 116, 36, 5, true, new Color(249,205,173), null, null);
            //写给浏览器
            ImageIO.write(bufferedImage, "JPEG", response.getOutputStream());
        }

    登录请求:

    <form action="${base}/login/main" method="post">
    
     <button class="layui-btn login_btn" lay-submit="" lay-filter="login">登录</button>
    @PostMapping("login/main")
        @ResponseBody
        @SysLog("用户登录")
        public RestResponse loginMain(HttpServletRequest request) {
            String username = request.getParameter("username");
            String password = request.getParameter("password");
            String rememberMe = request.getParameter("rememberMe");
            String code = request.getParameter("code");
            if(StringUtils.isBlank(username) || StringUtils.isBlank(password)){
                return RestResponse.failure("用户名或者密码不能为空");
            }
            if(StringUtils.isBlank(rememberMe)){
                return RestResponse.failure("记住我不能为空");
            }
            if(StringUtils.isBlank(code)){
                return  RestResponse.failure("验证码不能为空");
            }
            Map<String,Object> map = Maps.newHashMap();
            String error = null;
            HttpSession session = request.getSession();
            if(session == null){
                return RestResponse.failure("session超时");
            }
            String trueCode =  (String)session.getAttribute(Constants.VALIDATE_CODE);
            if(StringUtils.isBlank(trueCode)){
                return RestResponse.failure("验证码超时");
            }
            if(StringUtils.isBlank(code) || !trueCode.toLowerCase().equals(code.toLowerCase())){
                error = "验证码错误";
            }else {
                /*就是代表当前的用户。*/
                Subject user = SecurityUtils.getSubject();
                UsernamePasswordToken token = new UsernamePasswordToken(username,password,Boolean.valueOf(rememberMe));
                try {
                    user.login(token);
                    if (user.isAuthenticated()) {
                        map.put("url","index");
                    }
                }catch (IncorrectCredentialsException e) {
                    error = "登录密码错误.";
                } catch (ExcessiveAttemptsException e) {
                    error = "登录失败次数过多";
                } catch (LockedAccountException e) {
                    error = "帐号已被锁定.";
                } catch (DisabledAccountException e) {
                    error = "帐号已被禁用.";
                } catch (ExpiredCredentialsException e) {
                    error = "帐号已过期.";
                } catch (UnknownAccountException e) {
                    error = "帐号不存在";
                } catch (UnauthorizedException e) {
                    error = "您没有得到相应的授权!";
                }
            }
            if(StringUtils.isBlank(error)){
                return RestResponse.success("登录成功").setData(map);
            }else{
                return RestResponse.failure(error);
            }
        }

    登出

    @SysLog("退出系统")
        public String logOut(){
            SecurityUtils.getSubject().logout();
            return "redirect:/login";
        }
    String error = null;
    
    user.login(token);
                    if (user.isAuthenticated()) {
                        map.put("url","index");
                    }
    
    
    if(StringUtils.isBlank(error)){
                return RestResponse.success("登录成功").setData(map);
            }else{
                return RestResponse.failure(error);
            }

    如果登录成功会跳转到index.htlm

    否则返回错误信息

    看一下bean  RestResponse

    public class RestResponse extends HashMap<String, Object> {
        public static RestResponse success(){
            return success("成功");
        }
        public static RestResponse success(String message){
            RestResponse restResponse = new RestResponse();
            restResponse.setSuccess(true);
            restResponse.setMessage(message);
            return restResponse;
        }
    
        public static RestResponse failure(String message){
            RestResponse restResponse = new RestResponse();
            restResponse.setSuccess(false);
            restResponse.setMessage(message);
            return restResponse;
        }
    
    
        public RestResponse setSuccess(Boolean success) {
            if (success != null) put("success", success);
            return this;
        }
    
        public RestResponse setMessage(String message) {
            if (message != null) put("message", message);
            return this;
        }
    
        public RestResponse setData(Object data) {
            if (data != null) put("data", data);
            return this;
        }

    二、shiro 配置

    2.1 shiro - rdis 配置

    @Configuration
    public class ShiroConfig {
        private Logger  logger = LoggerFactory.getLogger(ShiroConfig.class);
    
        @Value("${spring.redis.host}")
        private String jedisHost;
    
        @Value("${spring.redis.port}")
        private Integer jedisPort;
    
        @Value("${spring.redis.password}")
        private String jedisPassword;
    
        @Bean
        public FilterRegistrationBean delegatingFilterProxy(){
            FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
            DelegatingFilterProxy proxy = new DelegatingFilterProxy();
            proxy.setTargetFilterLifecycle(true);
            proxy.setTargetBeanName("shiroFilter");
            filterRegistrationBean.setFilter(proxy);
            filterRegistrationBean.setDispatcherTypes(DispatcherType.ERROR,DispatcherType.REQUEST,DispatcherType.FORWARD,DispatcherType.INCLUDE);
            return filterRegistrationBean;
        }
    
        @Bean(name = "shiroFilter")
        public ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier("authRealm")AuthRealm authRealm){
            ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
            bean.setSecurityManager(securityManager(authRealm));
            bean.setSuccessUrl("/index");
            bean.setLoginUrl("/login");
            Map<String,Filter> map = Maps.newHashMap();
            map.put("authc",new CaptchaFormAuthenticationFilter());
            bean.setFilters(map);
            //配置访问权限
            LinkedHashMap<String, String> filterChainDefinitionMap = Maps.newLinkedHashMap();
            filterChainDefinitionMap.put("/static/**","anon");
            filterChainDefinitionMap.put("/showBlog/**","anon");
            filterChainDefinitionMap.put("/blog/**","anon");
            filterChainDefinitionMap.put("/login/main","anon");
            filterChainDefinitionMap.put("/genCaptcha","anon");
            filterChainDefinitionMap.put("/systemLogout","authc");
            filterChainDefinitionMap.put("/**","authc");
            bean.setFilterChainDefinitionMap(filterChainDefinitionMap);
            return bean;
        }
    
        @Bean
        public SecurityManager securityManager(@Qualifier("authRealm")AuthRealm authRealm){
            logger.info("- - - - - - -shiro开始加载- - - - - - ");
            DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
            defaultWebSecurityManager.setRealm(authRealm);
            defaultWebSecurityManager.setRememberMeManager(rememberMeManager());
            defaultWebSecurityManager.setSessionManager(webSessionManager());
            defaultWebSecurityManager.setCacheManager(cacheManager());
            return defaultWebSecurityManager;
        }
    
    
    
        @Bean
        public SimpleCookie rememberMeCookie(){
            //这个参数是cookie的名称,对应前端的checkbox的name = rememberMe
            SimpleCookie cookie = new SimpleCookie("rememberMe");
            cookie.setHttpOnly(true);
            //记住我有效期长达30天
            cookie.setMaxAge(2592000);
            return cookie;
        }
    
        @Bean
        public CookieRememberMeManager rememberMeManager(){
            CookieRememberMeManager rememberMeManager = new CookieRememberMeManager();
            rememberMeManager.setCookie(rememberMeCookie());
            rememberMeManager.setCipherKey(Base64.decode("2AvVhdsgUs0FSA3SDFAdag=="));
            return rememberMeManager;
        }
    
        /**
         * AOP式方法级权限检查
         * @return
         */
        @Bean
        public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator(){
            DefaultAdvisorAutoProxyCreator creator=new DefaultAdvisorAutoProxyCreator();
            creator.setProxyTargetClass(true);
            return creator;
        }
    
        /**
         * 保证实现了Shiro内部lifecycle函数的bean执行
         * @return
         */
        @Bean
        public static LifecycleBeanPostProcessor lifecycleBeanPostProcessor(){
            return new LifecycleBeanPostProcessor();
        }
    
        @Bean
        public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(@Qualifier("authRealm")AuthRealm authRealm) {
            SecurityManager manager= securityManager(authRealm);
            AuthorizationAttributeSourceAdvisor advisor=new AuthorizationAttributeSourceAdvisor();
            advisor.setSecurityManager(manager);
            return advisor;
        }
    
        @Bean
        public SessionManager webSessionManager(){
            DefaultWebSessionManager manager = new DefaultWebSessionManager();
            //设置session过期时间为1小时(单位:毫秒),默认为30分钟
            manager.setGlobalSessionTimeout(60 * 60 * 1000);
            manager.setSessionValidationSchedulerEnabled(true);
            manager.setSessionDAO(redisSessionDAO());
            return manager;
        }
    
        @Bean
        public RedisManager redisManager(){
            RedisManager manager = new RedisManager();
            manager.setHost(jedisHost);
            manager.setPort(jedisPort);
            //这里是用户session的时长 跟上面的setGlobalSessionTimeout 应该保持一直(上面是1个小时 下面是秒做单位的 我们设置成3600)
            manager.setExpire(60 * 60);
            manager.setPassword(jedisPassword);
            return manager;
        }
    
        @Bean
        public RedisSessionDAO redisSessionDAO(){
            RedisSessionDAO sessionDAO = new RedisSessionDAO();
            sessionDAO.setKeyPrefix("wl_");
            sessionDAO.setRedisManager(redisManager());
            return sessionDAO;
        }
    
        @Bean("myCacheManager")
        public RedisCacheManager cacheManager(){
            RedisCacheManager manager = new RedisCacheManager();
            manager.setRedisManager(redisManager());
            return manager;
        }
    }

    启用redis 缓存

    @EnableCaching
    @Configuration
    public class RedisCacheConfig {
    
        @Bean
        public RedisTemplate redisTemplate(RedisConnectionFactory factory) {
            StringRedisTemplate redisTemplate = new StringRedisTemplate(factory);
    
    //        JdkSerializationRedisSerializer jdkSerializationRedisSerializer = new JdkSerializationRedisSerializer();
            //这里如果启用fastjson序列化对象到redis的话 启动必须加参数 -Dfastjson.parser.autoTypeSupport=true
    //        RedisSerializer fastJson = fastJson2JsonRedisSerializer();
            Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
            ObjectMapper om = new ObjectMapper();
            om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
            om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
            jackson2JsonRedisSerializer.setObjectMapper(om);
            redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
            redisTemplate.afterPropertiesSet();
            return redisTemplate;
        }
    
        @Bean
        public CacheManager cacheManager(@SuppressWarnings("rawtypes") RedisTemplate redisTemplate) {
            return new RedisCacheManager(redisTemplate);
        }
    
    }

    认证和授权

    @Component(value = "authRealm")
    public class AuthRealm extends AuthorizingRealm {
    
        @Autowired
        @Lazy
        private UserService userService;
    
        @Override
        protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
            ShiroUser shiroUser = (ShiroUser)principalCollection.getPrimaryPrincipal();
            User user = userService.findUserByLoginName(shiroUser.getloginName());
            SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
            Set<Role> roles = user.getRoleLists();
            Set<String> roleNames = Sets.newHashSet();
            for (Role role : roles) {
                if(StringUtils.isNotBlank(role.getName())){
                    roleNames.add(role.getName());
                }
            }
            Set<Menu> menus = user.getMenus();
            Set<String> permissions = Sets.newHashSet();
            for (Menu menu : menus) {
                if(StringUtils.isNotBlank(menu.getPermission())){
                    permissions.add(menu.getPermission());
                }
            }
            info.setRoles(roleNames);
            info.setStringPermissions(permissions);
            return info;
        }
    
        @Override
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
            UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
    
            String username = (String)token.getPrincipal();
            User user = userService.findUserByLoginName(username);
            if(user == null) {
                throw new UnknownAccountException();//没找到帐号
            }
            if(Boolean.TRUE.equals(user.getLocked())) {
                throw new LockedAccountException(); //帐号锁定
            }
            byte[] salt = Encodes.decodeHex(user.getSalt());
            SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(
                    new ShiroUser(user.getId(),user.getLoginName(),user.getNickName(), user.getIcon()),
                    user.getPassword(), //密码
                    ByteSource.Util.bytes(salt),
                    getName()  //realm name
            );
            return authenticationInfo;
        }

     

    密码处理

        /**
         * Hex编码.
         */
        public static String encodeHex(byte[] input) {
            return new String(Hex.encodeHex(input));
        }
    
        /**
         * Hex解码.
         */
        public static byte[] decodeHex(String input) {
            try {
                return Hex.decodeHex(input.toCharArray());
            } catch (DecoderException e) {
                throw Exceptions.unchecked(e);
            }
        }

  • 相关阅读:
    码农提高工作效率-黄博文
    myeclipse与tomcat,运行jsp程序
    Ultraedit和写字板修改Tomcat 6.0的server.xml不生效
    MySQL5.5.33对应的JDBC驱动包怎样使用?
    Java是用JDBC连接MySQL数据库
    myeclipse trial expired暂时解决办法
    Json数据使用及学习方法
    在C#中使用json字符串
    vs2012换肤功能,vs2012主题及自定义主题
    给Notepad++换主题
  • 原文地址:https://www.cnblogs.com/lyon91/p/9003536.html
Copyright © 2011-2022 走看看