springboot下使用shiro自定义filter的个人经验分享

目录
  • 目标
  • 步骤
    • 1.在pom.xml中添加shiro的依赖
    • 2.创建ShiroRealm.java
    • 3.创建ShiroConfiguration.java
    • 4.创建自定义的过滤器MyFilter.java
    • 5.步骤3中使用了自定义密码验证的方式
    • 6.步骤3中放开了对登录页/loginController的过滤
  • 个人经验

在springboot中使用shiro,由于没有了xml配置文件,因此使用的方法与spring中有些区别。在踩了无数个坑后,在此将springboot下使用shiro的步骤总结如下。

由于本人对shiro的了解不是很深入,在实现了工作需求后就没有继续研究了,因此可能存在遗漏的地方或有错误的地方,还请多包涵。

目标

  • 在springboot中使用shiro
  • 1.实现用户的登录验证
  • 2.对于一些指定的url使用自定义的filter验证方式(不再使用shiro的realm验证)

步骤

1.在pom.xml中添加shiro的依赖

<dependency>
   <groupId>org.apache.shiro</groupId>
   <artifactId>shiro-spring</artifactId>
   <version>1.3.2</version>
</dependency>

2.创建ShiroRealm.java

继承AuthorizingRealm类,重写登录认证方法与授权方法

import User;
import UserService;
import org.apache.shiro.authc.*;
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.springframework.beans.factory.annotation.Autowired;
import java.util.ArrayList;
import java.util.List;

public class ShiroRealm extends AuthorizingRealm {
    //自己编写的service,注入,执行数据库查询方法用
    @Autowired
    private UserService userService;
    //认证.登录
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        UsernamePasswordToken utoken=(UsernamePasswordToken) token;//获取用户输入的token
        String username = utoken.getUsername();
        //这个User对象为自定义的JavaBean,使用userService从数据库中得到User对象(包含用户名、密码、权限3个字段)
        User user = userService.findUserByUserName(username);
        return new SimpleAuthenticationInfo(user, user.getPassword(),this.getClass().getName());//放入shiro.调用CredentialsMatcher检验密码
    }
    //授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principal) {
        User user=(User) principal.fromRealm(this.getClass().getName()).iterator().next();//获取session中的用户
        List<String> permissions=new ArrayList<>();
        //使用自定义的user对象获得权限字段,string类型,装入集合
        permissions.add(user.getRole());

        SimpleAuthorizationInfo info=new SimpleAuthorizationInfo();
        info.addStringPermissions(permissions);//将权限放入shiro中.(我的代码中其实没有用到权限相关)
        return info;
    }
}

3.创建ShiroConfiguration.java

使用@Configuration注解,是shiro的配置类,类似xml

import java.util.LinkedHashMap;
import java.util.Map;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.servlet.Filter;

@Configuration
public class ShiroConfiguration {
    @Bean
    public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager){
        ShiroFilterFactoryBean shiroFilterFactoryBean  = new ShiroFilterFactoryBean();
        // 必须设置 SecurityManager
        shiroFilterFactoryBean.setSecurityManager(securityManager);

        /*重要,设置自定义拦截器,当访问某些自定义url时,使用这个filter进行验证*/
        Map<String, Filter> filters = new LinkedHashMap<String, Filter>();
        //如果map里面key值为authc,表示所有名为authc的过滤条件使用这个自定义的filter
        //map里面key值为myFilter,表示所有名为myFilter的过滤条件使用这个自定义的filter,具体见下方
        filters.put("myFilter", new MyFilter());
        shiroFilterFactoryBean.setFilters(filters);
        /*---------------------------------------------------*/

        //拦截器
        Map<String,String> filterChainDefinitionMap = new LinkedHashMap<String,String>();
        //配置退出过滤器,其中的具体的退出代码Shiro已经替我们实现了
        filterChainDefinitionMap.put("/logout", "logout");
        //  anon:所有url都都可以匿名访问;
        //  authc: 需要认证才能进行访问;
        //  user:配置记住我或认证通过可以访问;
        //放开静态资源的过滤
        filterChainDefinitionMap.put("/css/**", "anon");
        filterChainDefinitionMap.put("/js/**", "anon");
        filterChainDefinitionMap.put("/img/**", "anon");
        //放开登录url的过滤
        filterChainDefinitionMap.put("/loginController", "anon");
        ///
        //对于指定的url,使用自定义filter进行验证
        filterChainDefinitionMap.put("/targetUrl", "myFilter");
        //可以配置多个filter,用逗号分隔,按顺序过滤,下方表示先通过自定义filter的验证,再通过shiro默认过滤器的验证
        //filterChainDefinitionMap.put("/targetUrl", "myFilter,authc");
        ///
        //过滤链定义,从上向下顺序执行,一般将 /**放在最为下边
        //url从上向下匹配,当条件匹配成功时,就会进入指定filter并return(不会判断后续的条件),因此这句需要在最下边
        filterChainDefinitionMap.put("/**", "authc");

        //如果不设置默认会自动寻找Web工程根目录下的"/login.jsp"页面
        shiroFilterFactoryBean.setLoginUrl("/login");
        // 登录成功后要跳转的链接
        shiroFilterFactoryBean.setSuccessUrl("/loginSuccess");
        // 未授权界面
        shiroFilterFactoryBean.setUnauthorizedUrl("/403");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        return shiroFilterFactoryBean;
    }

    @Bean
    public SecurityManager securityManager(){
        DefaultWebSecurityManager securityManager =  new DefaultWebSecurityManager();
        return securityManager;
    }
    //配置核心安全事务管理器
    @Bean(name="securityManager")
    public SecurityManager securityManager(@Qualifier("shiroRealm") ShiroRealm shiroRealm) {
        DefaultWebSecurityManager manager=new DefaultWebSecurityManager();
        manager.setRealm(shiroRealm);
        return manager;
    }
    //配置自定义的权限登录器
    @Bean(name="shiroRealm")
    public ShiroRealm shiroRealm(@Qualifier("credentialsMatcher") CredentialsMatcher matcher) {
        ShiroRealm shiroRealm=new ShiroRealm();
        shiroRealm.setCredentialsMatcher(matcher);
        return shiroRealm;
    }
    //配置自定义的密码比较器
    @Bean(name="credentialsMatcher")
    public CredentialsMatcher credentialsMatcher() {
        return new CredentialsMatcher();
    }
}

4.创建自定义的过滤器MyFilter.java

继承AccessControlFilter类,在步骤3中使用

import org.apache.commons.lang.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.AccessControlFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.util.Enumeration;
import java.util.Properties;
import java.util.Set;
public class MyFilter extends AccessControlFilter {
    private static Logger log = LoggerFactory.getLogger(MyFilter.class);

    //判断是否拦截,false为拦截,true为允许
    @Override
    public boolean isAccessAllowed(ServletRequest req, ServletResponse resp, Object object) throws Exception {
        Subject subject = getSubject(req,resp);
        String url = getPathWithinApplication(req);
        log.info("当前用户正在访问的url为 " + url);
        log.info("subject.isPermitted(url);"+subject.isPermitted(url));
        //可自行根据需要判断是否拦截,可以获得subject判断用户权限,也可以使用req获得请求头请求体信息
        //return true;
        return false;
    }

    //上面的方法返回false后(被拦截),会进入这个方法;这个方法返回false表示处理完毕(不放行);返回true表示需要继续处理(放行)
    @Override
    public boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
        //从req中获得的值,也可以自己使用其它判断是否放行的方法
        String username = request.getParameter("name");
        String password = request.getParameter("password");
        //创建token对象
        UsernamePasswordToken usernamePasswordToken=new UsernamePasswordToken(username,password);
        Subject subject = SecurityUtils.getSubject();
        try {
            //使用subject对象的login方法验证该token能否登录(使用方法2中的shiroRealm.java中的方法验证)
            subject.login(usernamePasswordToken);
        } catch (Exception e) {
            //log.info("登陆失败");
            //log.info(e.getMessage());
            return false;
        }
        //log.info("登陆成功");
        return true;
    }
}

5.步骤3中使用了自定义密码验证的方式

因此需要创建类CredentialsMatcher.java(与步骤3中的名称对应),继承SimpleCredentialsMatcher类

import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authc.credential.SimpleCredentialsMatcher;
public class CredentialsMatcher extends SimpleCredentialsMatcher {

    @Override
    public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
        UsernamePasswordToken utoken=(UsernamePasswordToken) token;
        //获得用户输入的密码:(可以采用加盐(salt)的方式去检验)
        String inPassword = new String(utoken.getPassword());
        //获得数据库中的密码
        String dbPassword=(String) info.getCredentials();
        //进行密码的比对
        return this.equals(inPassword, dbPassword);
    }
}

6.步骤3中放开了对登录页/loginController的过滤

因此我增加了一个ShiroController.java类

import User;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.HttpSession;

@Controller
public class ShiroController {
    @RequestMapping("/")
    public String loginPage() {
        return "login";
    }
    @RequestMapping("/login")
    public String login() {
        return "login";
    }
    @RequestMapping("/loginController")
    public String loginUser(String username,String password,HttpSession session) {
        UsernamePasswordToken usernamePasswordToken=new UsernamePasswordToken(username,password);
        Subject subject = SecurityUtils.getSubject();
        try {
            subject.login(usernamePasswordToken);   //完成登录
            //自定义的JavaBean,用于保存用户名、密码、权限3个字段
            User user=(User) subject.getPrincipal();
            //可选,可放入session,以备后续使用
            session.setAttribute("user", user);
            //跳转到登录成功页(controller)
            return "forward:/loginSuccess";
        } catch(Exception e) {
            //登录失败,跳转回登录页(html)
            return "login";
        }
    }
    @RequestMapping("/logOut")
    public String logOut(HttpSession session) {
        Subject subject = SecurityUtils.getSubject();
        subject.logout();
        //session.removeAttribute("user");
        return "login";
    }
}

个人经验

1.shiro配置类中的url拦截的执行顺序为从上到下,如果url匹配到一个规则,则会跳出匹配方法,忽略后续的匹配规则(相当于return)。

2.shiro使用自定义filter时,最好继承shiro的filter,不要直接继承Filter类。

3.shiro使用自定义filter时,map集合的key配置为"authc"、value配置为"new MyFilter()"时,表示对配置为authc的url使用自定义filter进行拦截,而不会使用ShiroRealm中的验证方法验证(可能是将shiro默认的authc的拦截器覆盖了);因此最好将key配置为其它自定义的字符串,将部分url的拦截规则设置为使用自定义filter拦截即可(如果仍想使用shiro默认的拦截器,可用逗号连接"authc")。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • Springboot-Shiro基本使用详情介绍

    目录 一.依据官网快速搭建Quickstart 1.1 配置pom.xml依赖 1.2配置log4j.properties 1.3 配置shiro.ini 1.4启动类 二.springboot结合shiro使用 2.1准备数据库 2.2配置yaml 三.实体类 3.1UserMapper即UserMapper.xml 四.shiro的配置类 五.启动类 5.1SecurityUtils. getSubject() Apache Shiro官网:https://shiro.apache.org/

  • springboot整合shiro之thymeleaf使用shiro标签的方法

    thymeleaf介绍 简单说, Thymeleaf 是一个跟 Velocity.FreeMarker 类似的模板引擎,它可以完全替代 JSP .相较与其他的模板引擎,它有如下三个极吸引人的特点: 1.Thymeleaf 在有网络和无网络的环境下皆可运行,即它可以让美工在浏览器查看页面的静态效果,也可以让程序员在服务器查看带数据的动态页面效果.这是由于它支持 html 原型,然后在 html 标签里增加额外的属性来达到模板+数据的展示方式.浏览器解释 html 时会忽略未定义的标签属性,所以 t

  • springboot使用shiro-整合redis作为缓存的操作

    说在前面 本来的整合过程是顺着博客的顺序来的,越往下,集成的越多,由于之前是使用ehcache缓存,现在改为redis,限制登录人数 以及 限制登录次数等 都需要改动,本篇为了简单,目前先将这两个功能下线,配置暂时是注销的,原类保存,在下篇博客中改. 还有之前是使用SessionListener监听session创建来统计在线人数,在本篇中也将改为统计redis中的key数目. 如果是单机,使用ehcache是最快的,项目一般都不是单节点,为了方便之后使用sso单点登录,以及多节点部署,所以使用

  • springboot下使用shiro自定义filter的个人经验分享

    目录 目标 步骤 1.在pom.xml中添加shiro的依赖 2.创建ShiroRealm.java 3.创建ShiroConfiguration.java 4.创建自定义的过滤器MyFilter.java 5.步骤3中使用了自定义密码验证的方式 6.步骤3中放开了对登录页/loginController的过滤 个人经验 在springboot中使用shiro,由于没有了xml配置文件,因此使用的方法与spring中有些区别.在踩了无数个坑后,在此将springboot下使用shiro的步骤总结

  • Linux下Squid代理服务器的架设与维护经验分享

    通过架设专门的WWW(FTP)代理来满足用户的主要需求,通过架设socks5代理来满足用户的其他需求. 一.对使用者的分析 现有网络情况: 我校校园网通过光缆已将31座建筑物连通,光缆总长度约15Km,绝大多数楼中实现结构化布线,连入校园网的网络多媒体教室.教学基地.实验室.机房等约有数十个,连网计算机达3000多台 .我校目前出口有2个,一条速率为10M bps,通过光纤接入中国教育科研网CERNET,另一条速率为4M bps连入中国电信. 用户的需求: 我校校园网的使用者主体为在校学生及老师

  • springboot集成shiro遭遇自定义filter异常的解决

    目录 springboot集成shiro遭遇自定义filter异常 1.用maven添加shiro 2.配置shiro 3.实现自定义的Realm.filter.SubjectFactory等 4.重点记录filter配置中出现的问题 5.解决方案 shiro自定义异常无效 springboot集成shiro遭遇自定义filter异常 首先简述springboot使用maven集成shiro 1.用maven添加shiro <!--shiro--> <dependency> <

  • springboot集成shiro自定义登陆过滤器方法

    目录 前言 自定义UsernamePasswordAuthenticationFilter 覆盖默认的FormAuthenticationFilter 完整UsernamePasswordAuthenticationFilter代码 前言 在上一篇博客springboot集成shiro权限管理简单实现中,用户在登录的过程中,有以下几个问题: 用户在没有登陆的情况下,访问需要权限的接口,服务器自动跳转到登陆页面,前端无法控制: 用户在登录成功后,服务器自动跳转到成功页,前端无法控制: 用户在登录失

  • spring-boot实现增加自定义filter(新)

    前言 传统的javaEE增加Filter是在web.xml中配置,如以下代码: <filter> <filter-name>TestFilter</filter-name> <filter-class>com.cppba.filter.TestFilter</filter-class> </filter> <filter-mapping> <filter-name>TestFilter</filter-n

  • 在SpringBoot下读取自定义properties配置文件的方法

    SpringBoot工程默认读取application.properties配置文件.如果需要自定义properties文件,如何读取呢? 一.在resource中新建.properties文件 在resource目录下新建一个config文件夹,然后新建一个.properties文件放在该文件夹下.如图remote.properties所示 二.编写配置文件 remote.uploadFilesUrl=/resource/files/ remote.uploadPicUrl=/resource

  • SpringBoot之自定义Filter获取请求参数与响应结果案例详解

    一个系统上线,肯定会或多或少的存在异常情况.为了更快更好的排雷,记录请求参数和响应结果是非常必要的.所以,Nginx 和 Tomcat 之类的 web 服务器,都提供了访问日志,可以帮助我们记录一些请求信息. 本文是在我们的应用中,定义一个Filter来实现记录请求参数和响应结果的功能. 有一定经验的都知道,如果我们在Filter中读取了HttpServletRequest或者HttpServletResponse的流,就没有办法再次读取了,这样就会造成请求异常.所以,我们需要借助 Spring

  • SpringBoot详解shiro过滤器与权限控制

    目录 shiro过滤器 权限控制 动态配置权限 shiro过滤器 首先从客户端发来的所有请求都经过Shiro过滤器,如果用户没有认证的都打回去进行认证,认证成功的,再判断是否具有访问某类资源(公有资源,私有资源)的权限,如果没有权限,访问失败;如果有权限访问成功.注意:客户端传来的token要和realm中的认证信息进行相同规则的比较(加密算法要一致). 常见过滤器: 1.在shiro配置类中配置,使用 filterFactoryBean.setFilterChainDefinitionMa()

  • springmvc+shiro自定义过滤器的实现代码

    实现需求: 1.用户未登录,跳转到登录页,登录完成后会跳到初始访问页. 2.用户自定义处理(如需要激活),跳转到激活页面,激活完成后会跳到初始访问页. 使用到的框架 springmvc 的拦截器 shiro 自定义过滤器 实现: 1.编写拦截器通过session保存初始访问的页面地址,便于后面回跳这个页面做准备. import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.web.serv

  • 基于springboot实现整合shiro实现登录认证以及授权过程解析

    这篇文章主要介绍了基于springboot实现整合shiro实现登录认证以及授权过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 1.添加shiro的依赖 <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring-boot-web- starter</artifactId> <version&g

随机推荐