Spring boot+Shiro身份认证失败返回JSON,不跳转页面

文章目录

  • 前言
  • 步骤
  • 1、重写FormAuthenticationFilter
  • 2、注册自定义过滤器

前言

shiro在进行身份认证时,如果失败了,默认会跳转到Web工程根目录下的"/login.jsp"页面,如果在配置类中配置了这句话:

shiroFilterFactoryBean.setLoginUrl("/myLogin");

认证失败后会跳转到setLoginUrl这个方法指定的路径中。

这里说的跳转,其实就是重定向

但是这样非常不灵活,如果是前后端分离的话,可能就会报错404了。

现在呢,我们想要在身份认证失败后不跳转页面,而是返回JSON数据,让前端自由的控制跳转到什么页面。

步骤

  1. 重写FormAuthenticationFilter 过滤器,然后重写它的onAccessDenied 方法。
  2. 注册我们刚刚重写的这个过滤器.

1、重写FormAuthenticationFilter

public class MyFormAuthenticationFilter extends FormAuthenticationFilter {

    @Override
    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
        HttpServletResponse httpServletResponse = (HttpServletResponse) response;
        httpServletResponse.setStatus(200);
        httpServletResponse.setContentType("application/json;charset=utf-8");

        PrintWriter out = httpServletResponse.getWriter();
        JSONObject json = new JSONObject();
        json.put("state","403");
        json.put("msg","登录已失效,请重新登录!");
        out.println(json);
        out.flush();
        out.close();
        return false;
    }
}
  1. 首先使用httpServletResponse 设置http的状态码与内容格式。
  2. 接着创建一个打印流。
  3. 实例化一个JSON对象,用来装数据
  4. 封装数据
  5. 输出

这里提一下为什么设置了两个状态值,一个是http的状态值,一个是json对象里面的一个状态值。
原因很简单,http的状态值只用来表示这次http请求的状态,与业务逻辑无关,这也是我为什么在json对象里面还要单独写一个状态值,将其分开。
现在很多开发者将其混淆、滥用,这是很不规范的。举个例子,比如用户密码错误这个场景,有的人直接把http状态码写成500,500表示的意思是Internal Server Error(请求未完成。服务器遇到不可预知的情况。换句话说就是服务器内部错误),可是用户密码错误时服务器内部错误吗?显然不是! 所以要分开使用。

2、注册自定义过滤器

由于这篇文章讲的是Spring boot+Shiro,所以这里就只展示Spring boot在配置类中的写法,Spring的xml配置文件写法就不写了,但是思想是一致的。

	@Bean
    public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager){
        // 创建 ShiroFilterFactoryBean
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();

        /* ************* 注册自定义授权过滤器 开始******************/
		
        // 1、创建过滤器Map,用来装自定义过滤器
        LinkedHashMap map = new LinkedHashMap<>();

        // 2、将自定义过滤器放入map中,如果实现了自定义授权过滤器,那就必须在这里注册,否则Shiro不会使用自定义的授权过滤器
        map.put("authc", new MyFormAuthenticationFilter());

        // 3、将过滤器Ma绑定到shiroFilterFactoryBean上
        shiroFilterFactoryBean.setFilters(map);
		
        /* ************* 注册自定义授权过滤器 结束******************/

		//此处省略其他配置
		......
		
        return shiroFilterFactoryBean;
    }

特别注意:这里map的key值不是随便写的,是要按照Shiro内置的FilterChain的Filter Name来写。
Shiro 内置的 FilterChain

Filter Name Class
anon org.apache.shiro.web.filter.authc.AnonymousFilter
authc org.apache.shiro.web.filter.authc.FormAuthenticationFilter
authcBasic org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter
perms org.apache.shiro.web.filter.authz.PermissionsAuthorizationFilter
port org.apache.shiro.web.filter.authz.PortFilter
rest org.apache.shiro.web.filter.authz.HttpMethodPermissionFilter
roles org.apache.shiro.web.filter.authz.RolesAuthorizationFilter
ssl org.apache.shiro.web.filter.authz.SslFilter
user org.apache.shiro.web.filter.authc.UserFilter

这里我继承了org.apache.shiro.web.filter.authc.FormAuthenticationFilter,那就得写 “authc”。

如果要重写权限验证器,就重写 PermissionsAuthorizationFilter 在注册时的key写:perms
如果要重写角色验证器,就重写 RolesAuthorizationFilter 在注册时的key写:roles


技 术 无 他, 唯 有 熟 尔。
知 其 然, 也 知 其 所 以 然。
踏 实 一 些, 不 要 着 急, 你 想 要 的 岁 月 都 会 给 你。


你可能感兴趣的:(Java)