前言

今天跟小伙伴们分享一个实战内容,使用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认证,这就是我们的第一步。

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

这就代表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认证就已经实现了。

测试部分

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

我们来抓取一下请求情况

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

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

使用PostMan测试一下

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

总结

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

给大家留下一个思考题,你认为这种Basic认证能够保证接口的安全吗?

欢迎大家留言讨论。

往期文章推荐:

JVM专栏

消息中间件专栏

并发编程专栏

Shiro实现Basic认证的更多相关文章

  1. SpringBoot&Shiro实现用户认证

    SpringBoot&Shiro实现用户认证 实现思路 思路:实现认证功能主要可以归纳为3点 1.定义一个ShiroConfig配置类,配置 SecurityManager Bean , Se ...

  2. [ASP.NET MVC] 利用自定义的AuthenticationFilter实现Basic认证

    很多情况下目标Action方法都要求在一个安全上下文中被执行,这里所谓的安全上下文主要指的是当前请求者是一个经过授权的用户.授权的本质就是让用户在他许可的权限范围内做他能够做的事情,授权的前提是请求者 ...

  3. iOS进行Basic认证与NTLM认证

    一.iOS进行Basic认证 只需要在NSMutableURLRequest的Header中添加认证所需的Username和password. NSMutableURLRequest *webReq ...

  4. Nginx 配置 Basic 认证

    /* * 环境:LNMP(CentOS 6.6 + Nginx 1.8.0) */ 在 Nginx 下配置 Basic 认证需要依靠 Nginx 的 http_auth_basic_module 模块 ...

  5. Apache 配置 Basic 认证

    /* * 环境:WAMP( Windows7 + WampServer2.2(Apache 2.2.21)) */ 配置过程: ① 生成用户文件,文件路径可以使用绝对路径,也可以使用相对路径 进入 a ...

  6. Basic认证

    Basic 概述 Basic 认证是HTTP 中非常简单的认证方式,因为简单,所以不是很安全,不过仍然非常常用. 当一个客户端向一个需要认证的HTTP服务器进行数据请求时,如果之前没有认证过,HTTP ...

  7. Http Basic认证

    Http Basic认证就是访问的时候把用户名和密码用base64加密放在request的header的authorization中 服务端直接获取authorization,解析,跟用户名匹配即可. ...

  8. Burpsuite之Http Basic认证爆破

    有的时候经常遇到401.今天正好朋友问怎么爆破,也顺便记录一下 怕忘记了 referer:http://www.2cto.com/Article/201303/194449.html 看到Burpsu ...

  9. HTTP使用BASIC认证的原理及实现方法

    一.   BASIC认证概述 在HTTP协议进行通信的过程中,HTTP协议定义了基本认证过程以允许HTTP服务器对WEB浏览器进行用户身份证的方法,当一个客户端向HTTP服务器进行数据请求时,如果客户 ...

随机推荐

  1. Python3 Socket

    Socket socket介绍 socket意为套接字,是应用层与传输层TCP/IP,UDP之间通信的中间软件抽象层,它是一组接口.使用时只需遵循socket的格式与规定去编程,让socket组织数据 ...

  2. FL Studio中的文件设置介绍

    在fl中,我们想要找到文件设置选项,可以在主菜单中选择选项-文件设置来打开,也可以通过按"F10"快捷键来一步打开." 文件设置"页面可以将其他文件夹链接到浏览 ...

  3. 思维导图软件iMindMap的使用方法

    从手绘的思维导图再到各种各样的思维导图的软件,思维导图的高效性大家都体会到了.思维导图软件iMindMap在众多导图软件中是最受欢迎的之一,下面就给大家分享一下思维导图怎么画: 首先我要教给大家的是如 ...

  4. 开始使用 java8 的日期工具类

    例如,现有的类(例如java.util.Date和SimpleDateFormatter)不是线程安全的,这会导致用户潜在的并发问题.而新的LocalDate.LocalDateTime.DateTi ...

  5. vue前端静态页面Github Pages线上预览实现

    一.前期准备之项目编译 此处记录如何解决vue2.0 打包之后,打开index.html出现空白页的问题,附上@参考地址 打包之前修改三个文件 第一步,找到build文件,在webpack.prod. ...

  6. sentinel整合servlet

    <dependency> <groupId>com.alibaba.csp</groupId> <artifactId>sentinel-web-ser ...

  7. CPU实现原子操作的原理

    586之前的CPU, 会通过LOCK锁总线的形式来实现原子操作. 686开始则提供了存储一致性(Cache coherence),  这是多处理的基础, 也是原子操作的基础. 1. 存储的粒度 存储的 ...

  8. Robot Framework接口自动化案例分享⑦——Jenkins持续集成

    一.RobotFramework插件安装 1.Jenkins首页->系统管理->插件管理->可选插件-> 2.搜索robot,点击直接安装 二.任务参数配置 1.新建任务 Je ...

  9. Java虚拟机之内存区域

    原创文章,转载请标明出处! 目录 一.背景 二.运行时内存区域概述 1.官方描述 2.中文翻译 3.内存区域简述 4.运行时数据区简图 5.运行时数据区详图 三.JVM线程 JVM数据区域与线程关系 ...

  10. 第八章 Python类中常用的特殊变量和方法

    上章花了近三十章节介绍类的知识,本章估计内容也比较多,讲完这些,其实还有更多.为什么这么多类有关的知识呢,这是因为在Python里面一切皆对象,就连整型.浮点数.字符串这些比较常规的类型都是作为类来实 ...