【Shiro】4、Shiro实现记住登录功能

简介: 用户每次在登录系统时需要重新输入账户、密码、验证码等信息,非常麻烦,于是要求加一个记住登录的功能,这对于 Shiro 来说是非常简单,下面就让我们一起来实现记住登录功能

一、使用场景

在登录界面,我们需要放置记住登录的选择框,当用户勾选“记住登录”后,在用户下次打开浏览器进入系统时,能够无感登录,即不需要进入到登录界面输入用户信息

二、功能开发

  • 1、当用户勾选“记住登录”后,我们在登录接口需要接受是否记住登录这个参数
@ApiOperation(value = "登录验证")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "account", value = "账号", required = true),
            @ApiImplicitParam(name = "password", value = "密码", required = true),
            @ApiImplicitParam(name = "resCode", value = "验证码", required = true),
            @ApiImplicitParam(name = "rememberMe", value = "记住登录", required = true)
    })
    @PostMapping("doLogin")
    @ResponseBody
    public R doLogin(@RequestBody LoginVO loginVO, HttpServletRequest request) {
        // 验证码
        if (!KaptchaUtil.validate(loginVO.getResCode(), request)) {
            return R.no(StatusEnums.KAPTCH_ERROR);
        }
        try {
            //获取当前的用户
            Subject subject = SecurityUtils.getSubject();
            // 验证帐号和密码,记住登录
            UsernamePasswordToken token = new UsernamePasswordToken(loginVO.getAccount(), loginVO.getPassword(), loginVO.getRememberMe());
            // 执行登录
            subject.login(token);
            // 将用户保存到session中
            request.getSession().setAttribute(SystemConst.SYSTEM_USER_SESSION, ShiroUtils.getSysUserInfo());
            // 保存登录日志
            sysLoginLogService.save(loginVO.getAccount(), 0, "用户登录成功");
            return R.ok("登录成功,欢迎回来!");
        } catch (UnknownAccountException e) {
            sysLoginLogService.save(loginVO.getAccount(), 1, "登录账户不存在");
            return R.no("账户不存在");
        } catch (DisabledAccountException e) {
            sysLoginLogService.save(loginVO.getAccount(), 1, "登录账户已被冻结");
            return R.no("账户已被冻结");
        } catch (IncorrectCredentialsException e) {
            sysLoginLogService.save(loginVO.getAccount(), 1, "登录密码不正确");
            return R.no("密码不正确");
        } catch (ExcessiveAttemptsException e) {
            sysLoginLogService.save(loginVO.getAccount(), 1, "密码连续输入错误超过5次,锁定半小时");
            return R.no("密码连续输入错误超过5次,锁定半小时");
        } catch (RuntimeException e) {
            sysLoginLogService.save(loginVO.getAccount(), 1, "未知错误");
            return R.no("未知错误");
        }
    }

这样我们在 UsernamePasswordToken 对象里多传入了一个 rememberMe 的参数,true 表示是,false 表示否

  • 2、注册 rememberMe 的cookie管理器
/**
     * 记住登录Cookie信息
     *
     * @return
     */
    @Bean
    public SimpleCookie rememberMeCookie() {
        SimpleCookie simpleCookie = new SimpleCookie("rememberMe");
        // 防止xss攻击,窃取cookie内容
        simpleCookie.setHttpOnly(true);
        // 30天有效期
        simpleCookie.setMaxAge(30 * 24 * 60 * 60);
        return simpleCookie;
    }

因我我们记住登录的信息是放置在 cookie 对象中,所以我们设置了记住登录的有效期为30天,30天过后,会失效,要求用户重新登录

  • 3、注册 rememberMe 管理对象
/**
     * 记住登录管理对象
     *
     * @return
     */
    @Bean
    public CookieRememberMeManager rememberMeManager() {
        CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();
        cookieRememberMeManager.setCookie(rememberMeCookie());
        cookieRememberMeManager.setCipherKey(Base64.decode("4BxVhuFKUs0KTA3Kprsdag=="));
        return cookieRememberMeManager;
    }

我们设置了管理器的 cookie 对象,和对信息加密的 key

  • 4、注入安全管理器
/**
 * 安全管理器
 */
@Bean
public SecurityManager securityManager() {
    DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
    // 设置自定义的relam
    securityManager.setRealm(loginRelam());
    // 设置记住登录管理器
    securityManager.setRememberMeManager(rememberMeManager());
    return securityManager;
}

5、修改地址过滤器

/**
 * 地址过滤器
 *
 * @param securityManager
 * @return
 */
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
    ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
    // 设置securityManager
    shiroFilterFactoryBean.setSecurityManager(securityManager);
    // 设置登录url
    shiroFilterFactoryBean.setLoginUrl("/login");
    // 设置主页url
    shiroFilterFactoryBean.setSuccessUrl("/");
    // 设置未授权的url
    shiroFilterFactoryBean.setUnauthorizedUrl("/403");
    Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
    // 注销登录
    filterChainDefinitionMap.put("/loginOut", "logout");
    // 开放登录接口
    filterChainDefinitionMap.put("/doLogin", "anon");
    // 开放获取登录验证码接口
    filterChainDefinitionMap.put("/kaptcha/**", "anon");
    // 开放Api接口
    filterChainDefinitionMap.put("/api/**", "anon");
    // 开放微信接口
    filterChainDefinitionMap.put("/weixin/**", "anon");
    // 开放websocket接口
    filterChainDefinitionMap.put("/websocket/**", "anon");
    // 开放接口文档
    filterChainDefinitionMap.put("/doc.html", "anon");
    filterChainDefinitionMap.put("/service-worker.js", "anon");
    filterChainDefinitionMap.put("/swagger-resources/**", "anon");
    filterChainDefinitionMap.put("/webjars/**", "anon");
    filterChainDefinitionMap.put("/v2/**", "anon");
    // 开放静态资源
    filterChainDefinitionMap.put("/css/**", "anon");
    filterChainDefinitionMap.put("/img/**", "anon");
    filterChainDefinitionMap.put("/js/**", "anon");
    filterChainDefinitionMap.put("/layui/**", "anon");
    filterChainDefinitionMap.put("/layuimini/**", "anon");
    filterChainDefinitionMap.put("/module/**", "anon");
    filterChainDefinitionMap.put("/upload/**", "anon");
    // 其余url全部拦截,必须放在最后
    filterChainDefinitionMap.put("/**", "user");
    shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
    return shiroFilterFactoryBean;
}

除了我们设置的 url 不拦截外,其余的 url 都会拦截,拦截规则为 user,拦截规则详解如下:

(1)anon:匿名过滤器,表示通过了url配置的资源都可以访问,例:“/statics/**=anon”表示statics目录下所有资源都能访问

(2)authc:基于表单的过滤器,表示通过了url配置的资源需要登录验证,否则跳转到登录,例:“/unauthor.jsp=authc”如果用户没有登录访问unauthor.jsp则直接跳转到登录

(3)authcBasic:Basic的身份验证过滤器,表示通过了url配置的资源会提示身份验证,例:“/welcom.jsp=authcBasic”访问welcom.jsp时会弹出身份验证框

(4)user:用户过滤器,表示可以使用登录验证/记住我的方式访问通过了url配置的资源,例:“/welcom.jsp=user”表示访问welcom.jsp页面可以通过登录验证或使用记住我后访问,否则直接跳转到登录

(5)logout:退出拦截器,表示执行logout方法后,跳转到通过了url配置的资源,例:“/logout.jsp=logout”表示执行了logout方法后直接跳转到logout.jsp页面

目录
相关文章
|
Java 数据库 数据安全/隐私保护
用shiro框架实现注册登陆,让你快速理解shiro用法
用shiro框架实现注册登陆,让你快速理解shiro用法
510 0
用shiro框架实现注册登陆,让你快速理解shiro用法
|
数据库 数据安全/隐私保护
8、SpringBoot2.0整合Shiro实现登录认证和权限管理(八)
添加相关的依赖,spring-boot-starter-data-jpa在 IEDA中创建SpringBoot2.0项目-超详细(一)博客中已经添加
156 0
8、SpringBoot2.0整合Shiro实现登录认证和权限管理(八)
|
存储 安全 Java
SpringBoot集成shiro认证,实现Shiro认证的登录操作
SpringBoot集成shiro认证,实现Shiro认证的登录操作
244 0
SpringBoot集成shiro认证,实现Shiro认证的登录操作
|
存储 缓存 安全
2021年你还不会Shiro?----2.Shiro实现登录功能(身份认证实践)
上一篇介绍了Shiro的架构,我们可以发现Shiro核心的东西并不多,我们花个几分钟就可以把Shiro的机构记清楚,其中Security Manager就是Shiro的核心,他包含了身份认证器Authenticator、授权器Authorizer、Session管理Session Manager、缓存管理Cache Manager。这一篇我们就介绍下Shiro的身份认证的过程,也就是我们说的用户登录。
162 0
2021年你还不会Shiro?----2.Shiro实现登录功能(身份认证实践)
|
存储 缓存 前端开发
2021年你还不会Shiro?----8.使用Shiro实现权限管理(前后端)
这是一个系列的文章,这是第八篇,如果只是看了这一篇或者对于Shiro没有基础的人,看到这一篇可能并不会有多大收益。前面几篇文章已经介绍了Shiro+JSP+SpringBoot+Mybatis+mysql的整合,并实现了使用MD5+盐+hash散列的方式对密码进行加密的注册登录功能。这篇是基于之前的文章进行写作的,下面就要说下登录完成后怎么实现授权操作。也就是怎么使用Shiro实现权限管理,前后端的授权是分开的,准确的说是没有关系的,所以这里也是对前后端的授权操作分开讲解。
389 0
2021年你还不会Shiro?----8.使用Shiro实现权限管理(前后端)
|
存储 缓存 开发框架
shiro会话管理
Shiro提供了完整的企业级会话管理功能,不依赖于底层容器(如Tomcat、WebLogic),不管是J2SE还是J2EE环境都可以使用,提供了会话管理,会话事件监听,会话存储/持久化,容器无关的集群,失效/过期支持,对Web的透明支持,SSO单点登录的支持等特性。
|
存储 缓存 安全
Shiro框架01之什么是shiro+shiro的架构+权限认证
Shiro框架01之什么是shiro+shiro的架构+权限认证
Shiro框架01之什么是shiro+shiro的架构+权限认证
|
程序员 数据库 数据安全/隐私保护
2021年你还不会Shiro?----5.使用Shiro实现授权功能
每个用户对系统的访问都会对应着身份认证,那么身份认证完了以后呢,自然就是对该用户进行授权,判断用户请求的资源是否拥有权限,或者从数据中获取该用户对应的角色,从而判断对应的资源,该用户是否可以访问。
97 0
|
Java 数据安全/隐私保护
【Shiro】1、Shiro实现登录授权认证功能(中)
之前在 SSM 项目中使用过 shiro,发现 shiro 的权限管理做的真不错,但是在 SSM 项目中的配置太繁杂了,于是这次在 SpringBoot 中使用了 shiro,下面一起看看吧
141 0
|
Java 数据安全/隐私保护
【Shiro】1、Shiro实现登录授权认证功能(下)
之前在 SSM 项目中使用过 shiro,发现 shiro 的权限管理做的真不错,但是在 SSM 项目中的配置太繁杂了,于是这次在 SpringBoot 中使用了 shiro,下面一起看看吧
141 0