Shiro的rememberMe功能

一般没有登录也可以查看各个板块
1.登录之后才能查看(拦截器/过滤器);2不同人操作的板块不一样(权限)
shiro框架
1.shiro的登录验证(过滤器)
2.记住我汇关闭浏览器后再次打开系统不需要登录,就可以访问项目,本地cookie存储了用户信息;

shiro的rememberMe功能

Shiro 提供了记住我(RememerMe)的功能,比如访问一些网站时,关闭了浏览器,下次再打开时还是能记住你是谁,下次访问时无需再登录即可访问。

例如:当没有登录时,访问/main主页,会被拦截跳转到登录页面。当登录后是可以正常访问/man的主页的,如果使用了记住我功能,会在浏览器写入cookie,关掉浏览器不需要登录即可直接访问/main.

基本流程

1.首先在登录页面选中RememberMe然后登录成功;如果是浏览器登录,一般会把RememberMe 的Cookie 写到客户端并保存下来;

2.关闭浏览器再重新打开,会发现浏览器还是记住你的;

3.访问一般的网页服务器端,仍然知道你是谁,且能正常访问;

4.但是,如果我们访问电商平台时,如果要查看我的订单或进行支付时,此时还 是需要再进行身份认证的,以确保当前用户还是你。

在springxml中配置cookie的设置和rememberMe管理器

1.配置记住我功能的cookie设置;

2.配置记住我功能的管理器;

3.在安全管理器中引用记住我功能的管理器;

4. 在过滤器中 shiroFilter 配置 rememberMe 的过滤配置( /**=user
<!--=================shiro相关配置====================-->
<!--配置shiro进行校验时的加密规则-->
<bean id="credentialsMatcher"
class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
<!--加密规则-->
<property name="hashAlgorithmName" value="MD5" />
<!--是否加盐-->
<property name="hashSalted" value="true" />
<!--是否增加哈希算法进行散列-->
<!-- <property name="hashIterations" value="1024" />-->
</bean>
<!--配置自定义Realm-->
<bean id="myRealm" class="com.chen.shiro.MyRealm">
<property name="credentialsMatcher" ref="credentialsMatcher" />
</bean>
<!--=================记住我功能相关配置====================-->
<!--记住我功能的cookie设置-->
<bean id="simpleCookie" class="org.apache.shiro.web.servlet.SimpleCookie">
<!--设置cookie的属性名-->
<property name="name" value="rememberMe" />
<!--设置cookie存在根目录,可在同一应用服务器内共享-->
<property name="path" value="/" />
<!--通过JavaScript脚本将无法读取到Cookie信息,这样能有效的防止XSS攻击,让网站应用更
加安全-->
<property name="httpOnly" value="true" />
<!--设置cookie的失效时间为30天-->
<property name="maxAge" value="2592000" />
</bean>
<!--记住我功能的管理器配置-->
<bean id="rememberMeManager"
class="org.apache.shiro.web.mgt.CookieRememberMeManager">
<!--引用cookie设置-->
<property name="cookie" ref="simpleCookie" />
<!--默认AES算法,设置cookie的加密算法,采用的是base64的加密-->
<property name="cipherKey" value="#
{T(org.apache.shiro.codec.Base64).decode('4AvVhmFLUs0KTA3Kprsdag==')}" />
</bean>
<!--配置安全管理器,使用自定义的Realm-->
<bean id="securityManager"
class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<!--配置自定义的Realm-->
<property name="realm" ref="myRealm" />
<!--====引用rememberMe功能管理器====================-->
<property name="rememberMeManager" ref="rememberMeManager" />
</bean>
<!-- 配置shiro的过滤器工厂类,id- shiroFilter要和我们在web.xml中配置的过滤器一致 -->
<bean id="shiroFilter"
class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<!-- 调用我们配置的权限管理器 -->
<property name="securityManager" ref="securityManager"/>
<!-- 配置拦截后我们的登录请求地址 -->
<property name="loginUrl" value="/loginUI"/>
<!-- 如果您请求的资源不再您的权限范围,则跳转到错误页面 -->
<property name="unauthorizedUrl" value="/error"/>
<!-- 权限配置 -->
<!-- 权限配置
anon:任何人都可以访问; authc:必须是登录之后才能进行访问,不包括remember
me;
perms:指定过滤规则,可以自己拓展权限配置; roles:配置角色;
user:登录用户才可以访问,包含remember me; logout:退出
-->
<property name="filterChainDefinitions">
<value>
/=anon
/index = anon
/loginUI = anon
/login = anon
/WEB-INF/view/login.html = anon
/**/*.js=anon
/**/*.css=anon
/**=authc
/**=user
</value>
</property>
</bean>
1、页面上添加勾选的复选框按钮,并设置 name 属性 rememberMe
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<div class="checkbox">
<label>
<input type="checkbox" name="rememberMe"> 记住我
</label>
</div>
</div>
</div>
2、修改 controller ,或者记住我功能是否勾选,认证时添加 记住我标记
1. 配置 boolean 类型的请求参数 rerememberMe ,并设置默认值是 false
2.在封装 token 时,加入 rerememberMe 标记;
@RequestMapping("/login")
    public String login(String uname, String pwd,@RequestParam(defaultValue = "false") boolean rememberMe, HttpSession session){
        //1 获取 Subject 对象
        Subject subject = SecurityUtils.getSubject();
        //2 封装请求数据到 token 对象中
        AuthenticationToken token = new UsernamePasswordToken(uname,pwd,rememberMe);
        //3 调用 login 方法进行登录认证
        try{
            //验证主体是否能够登录
            subject.login(token);
            session.setAttribute("user",token.getPrincipal().toString());
            return "main";
        }catch(UnknownAccountException e){
            System.out.println("用户名不存在!!");
            return "login";
        }catch(IncorrectCredentialsException e){
            System.out.println("密码错误!");
            return "login";
        }catch(AuthenticationException e){
            System.out.println("登录失败!");
            return "login";
        }
    }

3、测试rerememberMe功能

1.不登录直接访问主页/main,shiro会拦截去到登录页;登录后可以正常访问主页/main;

2.登录时不勾选记住我,关闭浏览器访问主页/main还会拦截到登录页;

3.登录时勾选记住我,关闭浏览器访问主页/main可以正常访问;
shiro 的登出
1. 在主页设置退出登录的链接
<a href="/logout">退出登录</a>
2. spring.xml 配置文件中找到 shiro 过滤器,配置登出的 操作
<property name="filterChainDefinitions">
<value>
/=anon
/index = anon
/loginUI = anon
/login = anon
/logout=logout
/WEB-INF/view/login.html = anon
/**/*.js=anon
/**/*.css=anon
/**=authc
/**=user
</value>
</property>
shiro 角色授权认证模拟
1. 在主页设计两个超链接,分别模拟查看用户管理和系统管
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>主页</title>
<body>
<a href="/logout">退出登录</a>
<hr/>
<ul>
    <li><a href="/user">用户管理</a></li>
    <li><a href="/system">系统管理</a></li>
</ul>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>用户管理界面</title>
</head>
<body>
<ul>
    <li><a href="/user/add">添加用户</a></li>
    <li><a href="/user/delete">删除用户</a></li>
    <li><a href="/user/find">查看用户</a></li>
    <li><a href="/user/revise">修改用户</a></li>
</ul>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>系统管理界面</title>
</head>
<body>
<ul>
    <li><a href="/system/set">系统设置</a></li>
    <li><a href="/system/upd">系统修改</a></li>
</ul>
</body>
</html>

2、在控制器中使用@RequiresRoles("roles")注解来开启请求的角色验证

package com.zhan.controller;

import com.zhan.service.UserService;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.apache.shiro.authz.annotation.RequiresRoles;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpSession;

@Controller
public class UserController {

    @RequestMapping("/login")
    public String login(String uname, String pwd,@RequestParam(defaultValue = "false") boolean rememberMe, HttpSession session){
        //1 获取 Subject 对象
        Subject subject = SecurityUtils.getSubject();
        //2 封装请求数据到 token 对象中
        AuthenticationToken token = new UsernamePasswordToken(uname,pwd,rememberMe);
        //3 调用 login 方法进行登录认证
        try{
            //验证主体是否能够登录
            subject.login(token);
            session.setAttribute("user",token.getPrincipal().toString());
            return "main";
        }catch(UnknownAccountException e){
            System.out.println("用户名不存在!!");
            return "login";
        }catch(IncorrectCredentialsException e){
            System.out.println("密码错误!");
            return "login";
        }catch(AuthenticationException e){
            System.out.println("登录失败!");
            return "login";
        }
    }

    @RequiresRoles("user")
    @RequestMapping("/user")
    public String user(){
        System.out.println("访问了用户管理请求");
        return "userList";
    }

    @RequiresRoles("admin")
    @RequestMapping("/system")
    public String system(){
        System.out.println("访问了系统管理请求");
        return "systemManager";
    }

    @RequiresPermissions("user:add")
    @RequestMapping("/user/add")
    @ResponseBody
    public String add(){
        System.out.println("用户添加操作");
        return "action user add...";
    }

    @RequiresPermissions("user:delete")
    @RequestMapping("/user/delete")
    @ResponseBody
    public String delete(){
        System.out.println("用户删除操作");
        return "action user delete...";
    }

    @RequiresPermissions("user:find")
    @RequestMapping("/user/find")
    @ResponseBody
    public String find(){
        System.out.println("用户查询操作");
        return "action user find...";
    }

    @RequiresPermissions("user:revise")
    @RequestMapping("/user/revise")
    @ResponseBody
    public String revise(){
        System.out.println("用户修改操作");
        return "action user revise...";
    }

}
3. springmvc.xml 中开启 shiro 的注解支持
由于shiro注解是在controller中配置,所以需要在 springmvc.xml 中配置shiro的注解支持:
1.配置shiro bean生命周期处理器
2.配置自动创建代理;
3.开启shiro注解的支持
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">

    <context:component-scan base-package="com.zhan.controller"/>

    <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/view/"/>
        <property name="suffix" value=".html"/>
    </bean>

    <!--配置文件解析器-->
    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <!--上传文件的最大size-->
        <property name="maxUploadSize" value="4194304"/>
    </bean>

    <mvc:resources mapping="/css/**" location="/css/"/>
    <mvc:resources mapping="/js/**" location="/js/"/>
    <mvc:resources mapping="/fonts/**" location="/fonts/"/>
    <mvc:resources mapping="/img/**" location="/img/"/>
<!--    <mvc:resources mapping="/layui/**" location="/layui/"/>-->
<!--    <mvc:resources mapping="/upload/**" location="/upload/"/>-->

    <mvc:annotation-driven/>

    <!--配置shiro bean生命周期处理器-->
    <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>
    <!--配置自动创建代理-->
    <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" depends-on="lifecycleBeanPostProcessor">
        <property name="proxyTargetClass" value="true" />
    </bean>
    <!-- 开启shiro注解的支持 -->
    <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
        <property name="securityManager" ref="securityManager" />
    </bean>



</beans>

MyRealm.java 

package com.zhan.shiro;

import com.zhan.bean.User;
import com.zhan.service.UserService;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * token 里面是客户端发来的信息(包含输入的用户名和密码
 * 自定义Realm,通过mybatis查询数据库的密码和盐值,让shiro进行身份验证
 */
@Component
public class MyRealm extends AuthorizingRealm {

    @Autowired
    UserService userService;

    /**
     * shiro 进行授权操作
     * @param principals
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        //打印
        System.out.println("realm的授权认证方法被执行==============");
        //1.创建角色和权限对象
        SimpleAuthorizationInfo authorizationInfo=new SimpleAuthorizationInfo();
        //2.判断用户是否有对应的角色 或者 权限 有则放行 没有则抛出异常
        //模拟操作---完成数据库操作
        //2.1获取登录用户
        String uname = principals.getPrimaryPrincipal().toString();
        System.out.println("当前登录用户为:"+uname);
        if(uname.equals("admin")){
            //正常查询用户的角色(数据库使用set)  模拟赋予角色
            String role = "admin";
            authorizationInfo.addRole(role);

            //授予权限正常查询该用户的权限,现在模拟赋予权限
            authorizationInfo.addStringPermission("user:add");
            authorizationInfo.addStringPermission("user:delete");
            authorizationInfo.addStringPermission("user:find");
            authorizationInfo.addStringPermission("user:revise");

        }else{
            //模拟添加角色
            authorizationInfo.addRole("user");
            authorizationInfo.addStringPermission("user:add");
            authorizationInfo.addStringPermission("user:find");
        }
        //返回权限
        return authorizationInfo;
    }

    /**
     * shiro 进行认证操作
     * @param token
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        //打印
        System.out.println("realm的登录认证方法被执行==============");
        //token 是主体传过来的身份令牌
        //1.获取用户身份信息
        String uname = token.getPrincipal().toString();
        //2.调用业务层获取永固信息(数据库中)
        User user = userService.selectByName(uname);
        //判断并将数据完成封装
        if(user!=null){
            AuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(
                    token.getPrincipal(),//令牌身份信息对象
                    user.getPwd(),//用户数据库的密码
                    ByteSource.Util.bytes(user.getSalt().getBytes()),//加密时的盐值
                    uname//用户名
            );
            return authenticationInfo;
        }
        return null;
    }
}

配置权限,点击用户管理,用户为admin,可以点击四个权限;否则只有两个权限;

shiro授权异常处理

1.创建认证异常处理类,使用@ControllerAdvice和@ExceptionHandler实现特殊异常处理

package com.zhan.controller;

import org.apache.shiro.authz.AuthorizationException;
import org.apache.shiro.authz.UnauthorizedException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;

/**
 * shiro的异常处理
 */
@ControllerAdvice
public class ShiroExceptionHandler {
    /**
     * 处理没有权限的异常
     * @param e
     * @return
     */
    @ExceptionHandler(UnauthorizedException.class)
    public String handlerUnauthorizedException(UnauthorizedException e){
        e.printStackTrace();
        return "403";
    }

    /**
     * 处理其他权限验证异常
     * @param e
     * @return
     */

    @ExceptionHandler(AuthorizationException.class)
    public String handlerAuthorizationException(AuthorizationException e){
        e.printStackTrace();
        return "403";
    }

}

2.测试出现权限异常时是否会被异常处理执行

 403.html页面

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>异常处理</title>
</head>
<body>
<h2>系统出现了异常,请联系管理员!!</h2>
</body>
</html>

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值