Spring Boot+Shiro实现一个Http请求的Basic认证

作者:H.U.C-王子 时间:2022-06-01 22:22:31 

目录
  • 前言

  • 实践部分

  • 测试部分

  • 总结

前言

今天跟小伙伴们分享一个实战内容,使用Spring Boot+Shiro实现一个简单的Http认证。

场景是这样的,我们平时的工作中可能会对外提供一些接口,如果这些接口不做一些安全认证,什么人都可以访问,安全性就太低了,所以我们的目的就是增加一个接口的认证机制,防止别人通过接口攻击服务器。

至于Shiro是什么,Http的Basic认证是什么,王子就简单介绍一下,详细内容请自行了解。

Shiro是一个Java的安全框架,可以简单实现登录、鉴权等等的功能。

Basic认证是一种较为简单的HTTP认证方式,客户端通过明文(Base64编码格式)传输用户名和密码到服务端进行认证,通常需要配合HTTPS来保证信息传输的安全。

实践部分

首先说明一下测试环境。

王子已经有了一套集成好Shiro的Spring Boot框架,这套框架详细代码就不做展示了,我们只来看一下测试用例。

要测试的接口代码如下:


/**
* @author liumeng
*/
@RestController
@RequestMapping("/test")
@CrossOrigin
public class TestAppController extends BaseController {
   /**
    * 数据汇总
    */
   @GetMapping("/list")
   public AjaxResult test()
   {
       return success("测试接口!");
   }
}

使用Shiro,一定会有Shiro的 * 配置,这部分代码如下:


/**
    * Shiro过滤器配置
    */
   @Bean
   public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager)
   {
       ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
       // Shiro的核心安全接口,这个属性是必须的
       shiroFilterFactoryBean.setSecurityManager(securityManager);
       // 身份认证失败,则跳转到登录页面的配置
       shiroFilterFactoryBean.setLoginUrl(loginUrl);
       // 权限认证失败,则跳转到指定页面
       shiroFilterFactoryBean.setUnauthorizedUrl(unauthorizedUrl);
       // Shiro连接约束配置,即过滤链的定义
       LinkedHashMap<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
       // 对静态资源设置匿名访问
       filterChainDefinitionMap.put("/favicon.ico**", "anon");
       filterChainDefinitionMap.put("/lr.png**", "anon");
       filterChainDefinitionMap.put("/css/**", "anon");
       filterChainDefinitionMap.put("/docs/**", "anon");
       filterChainDefinitionMap.put("/fonts/**", "anon");
       filterChainDefinitionMap.put("/img/**", "anon");
       filterChainDefinitionMap.put("/ajax/**", "anon");
       filterChainDefinitionMap.put("/js/**", "anon");
       filterChainDefinitionMap.put("/lr/**", "anon");
       filterChainDefinitionMap.put("/captcha/captchaImage**", "anon");
       // 退出 logout地址,shiro去清除session
       filterChainDefinitionMap.put("/logout", "logout");
       // 不需要拦截的访问
       filterChainDefinitionMap.put("/login", "anon,captchaValidate");
       filterChainDefinitionMap.put("/ssoLogin", "anon");// 开启Http的Basic认证
       filterChainDefinitionMap.put("/test/**", "authcBasic");
       // 注册相关
       filterChainDefinitionMap.put("/register", "anon,captchaValidate");

Map<String, Filter> filters = new LinkedHashMap<String, Filter>();
       filters.put("onlineSession", onlineSessionFilter());
       filters.put("syncOnlineSession", syncOnlineSessionFilter());
       filters.put("captchaValidate", captchaValidateFilter());
       filters.put("kickout", kickoutSessionFilter());
       // 注销成功,则跳转到指定页面
       filters.put("logout", logoutFilter());
       shiroFilterFactoryBean.setFilters(filters);

// 所有请求需要认证authcBasic
       filterChainDefinitionMap.put("/**", "user,kickout,onlineSession,syncOnlineSession");
       shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);

return shiroFilterFactoryBean;
   }

这里我们要关注的是代码中的

filterChainDefinitionMap.put("/test/**", "authcBasic");
这部分代码,它指定了我们的测试接口启动了Http的Basic认证,这就是我们的第一步。

做到这里我们可以尝试的去用浏览器访问一下接口,会发现如下情况:

Spring Boot+Shiro实现一个Http请求的Basic认证

这就代表Basic认证已经成功开启了,这个时候我们输入系统的用户名和密码,你以为它就能成功访问了吗?

答案是否定的,我们只是开启了认证,但并没有实现认证的逻辑。

王子通过阅读部分Shiro源码,发现每次发送请求后,都会调用ModularRealmAuthenticator这个类的doAuthenticate方法,源码如下:


protected AuthenticationInfo doAuthenticate(AuthenticationToken authenticationToken) throws AuthenticationException {
       assertRealmsConfigured();
       Collection<Realm> realms = getRealms();
       if (realms.size() == 1) {
           return doSingleRealmAuthentication(realms.iterator().next(), authenticationToken);
       } else {
           return doMultiRealmAuthentication(realms, authenticationToken);
       }
   }

可以看出,这个方法主要就是对Realm进行了管理,因为我们的系统本身已经有两个Ream了,针对的是不同情况的权限验证,所以为了使用起来不冲突,我们可以继承这个类来实现我们自己的逻辑,在配置类中增加如下内容即可:


@Bean
   public ModularRealmAuthenticator modularRealmAuthenticator(){
       //用自己重新的覆盖
       UserModularRealmAuthericator modularRealmAuthericator = new UserModularRealmAuthericator();
       modularRealmAuthericator.setAuthenticationStrategy(new AtLeastOneSuccessfulStrategy());
       return modularRealmAuthericator;
   }

然后在我们自己的UserModularRealmAuthericator类中重写doAuthenticate方法就可以了,这里面的具体实现逻辑就要看你们自己的使用场景了。

我们可以自己新创建一个Realm来单独校验Basic认证的情况,或者共用之前的Realm,这部分就自由发挥了。

大概内容如下:


public class UserModularRealmAuthericator extends ModularRealmAuthenticator {
   private static final Logger logger = LoggerFactory.getLogger(UserModularRealmAuthericator.class);

@Override
   protected AuthenticationInfo doAuthenticate(AuthenticationToken authenticationToken) throws AuthenticationException {
       assertRealmsConfigured();
       //强制转换返回的token
       UsernamePasswordToken  usernamePasswordToken = (UsernamePasswordToken) authenticationToken;//所有Realm
       Collection<Realm> realms = getRealms();
       //最终选择的Realm
       Collection<Realm> typeRealms = new ArrayList<>();
       for(Realm realm:realms){
           if(...){ //这部分是自己的逻辑判断,过滤出想要使用的Realm
               typeRealms.add(realm);
           }
       }
       //判断是单Realm 还是多Realm
       if(typeRealms.size()==1){
           return doSingleRealmAuthentication(typeRealms.iterator().next(),usernamePasswordToken);
       }else{
           return doMultiRealmAuthentication(typeRealms,usernamePasswordToken);
       }
   }
}

Realm的具体实现代码这里就不做演示了,无非就是判断用户名密码是否能通过校验的逻辑。如果不清楚,可以自行了解Realm的实现方式。

Realm校验实现后,Basic认证就已经实现了。

测试部分

接下来我们再次使用浏览器对接口进行测试,输入用户名和密码,就会发现接口成功响应了。

我们来抓取一下请求情况

Spring Boot+Shiro实现一个Http请求的Basic认证

可以发现,Request Header中有了Basic认证的信息Authorization: Basic dGVzdDoxMjM0NTY=

这部分内容是这样的,Basic为一个固定的写法,dGVzdDoxMjM0NTY=这部分内容是userName:Password组合后的Base64编码,所以我们只要给第三方提供这个编码,他们就可以通过编码访问我们的接口了。

使用PostMan测试一下

Spring Boot+Shiro实现一个Http请求的Basic认证

可以发现接口是可以成功访问的。

总结

到这里本篇文章就结束了,王子向大家仔细的介绍了如何使用Shiro实现一个Http请求的Basic认证,是不是很简单呢。

来源:https://www.cnblogs.com/lm970585581/p/14149342.html

标签:Spring,Boot,Shiro,Http请求,Basic认证
0
投稿

猜你喜欢

  • Android实现悬浮窗的简单方法实例

    2023-06-17 18:11:02
  • idea如何配置javafxsdk详细教程

    2023-11-24 22:04:16
  • Intellij IDEA + Android SDK + Genymotion Emulator打造最佳Android开发环境

    2023-06-17 06:47:11
  • SpringBoot防止大量请求攻击的实现

    2023-11-24 16:42:54
  • SpringBoot中多环境配置和@Profile注解示例详解

    2023-11-29 05:39:04
  • 深入学习Java编程中的字符串的进阶使用

    2023-11-11 12:54:20
  • jsp如何获取Session中的值

    2023-07-01 05:59:28
  • 15个顶级Java多线程面试题(附答案)

    2023-11-24 01:53:44
  • Flutter 通过Clipper实现各种自定义形状的示例代码

    2023-06-19 14:25:11
  • Spring Cache+Redis缓存数据的实现示例

    2023-11-26 11:53:20
  • Android实现腾讯新闻的新闻类别导航效果

    2023-07-29 04:17:46
  • Spring Data JPA 之 JpaRepository的使用

    2023-11-24 21:23:40
  • Android基础之使用Fragment控制切换多个页面

    2023-07-11 00:08:37
  • 分享Java常用开发编辑器工具

    2023-11-06 07:35:37
  • Android Handler消息机制分析

    2023-10-01 13:22:26
  • C++实现softmax函数的面试经验

    2023-06-16 02:07:47
  • mybatis plus新增(insert)数据获取主键id的问题

    2023-08-09 10:50:52
  • 一篇文章告诉你JAVA Mybatis框架的核心原理到底有多重要

    2023-11-13 06:20:10
  • SpringBoot常用数据库开发技术汇总介绍

    2023-11-11 09:39:22
  • JSON.toJSONString()空字段不忽略修改的问题

    2023-06-16 03:12:37
  • asp之家 软件编程 m.aspxhome.com