Shiro实现Basic认证
前言
今天跟小伙伴们分享一个实战内容,使用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认证能够保证接口的安全吗?
欢迎大家留言讨论。
往期文章推荐:

Shiro实现Basic认证的更多相关文章
- SpringBoot&Shiro实现用户认证
SpringBoot&Shiro实现用户认证 实现思路 思路:实现认证功能主要可以归纳为3点 1.定义一个ShiroConfig配置类,配置 SecurityManager Bean , Se ...
- [ASP.NET MVC] 利用自定义的AuthenticationFilter实现Basic认证
很多情况下目标Action方法都要求在一个安全上下文中被执行,这里所谓的安全上下文主要指的是当前请求者是一个经过授权的用户.授权的本质就是让用户在他许可的权限范围内做他能够做的事情,授权的前提是请求者 ...
- iOS进行Basic认证与NTLM认证
一.iOS进行Basic认证 只需要在NSMutableURLRequest的Header中添加认证所需的Username和password. NSMutableURLRequest *webReq ...
- Nginx 配置 Basic 认证
/* * 环境:LNMP(CentOS 6.6 + Nginx 1.8.0) */ 在 Nginx 下配置 Basic 认证需要依靠 Nginx 的 http_auth_basic_module 模块 ...
- Apache 配置 Basic 认证
/* * 环境:WAMP( Windows7 + WampServer2.2(Apache 2.2.21)) */ 配置过程: ① 生成用户文件,文件路径可以使用绝对路径,也可以使用相对路径 进入 a ...
- Basic认证
Basic 概述 Basic 认证是HTTP 中非常简单的认证方式,因为简单,所以不是很安全,不过仍然非常常用. 当一个客户端向一个需要认证的HTTP服务器进行数据请求时,如果之前没有认证过,HTTP ...
- Http Basic认证
Http Basic认证就是访问的时候把用户名和密码用base64加密放在request的header的authorization中 服务端直接获取authorization,解析,跟用户名匹配即可. ...
- Burpsuite之Http Basic认证爆破
有的时候经常遇到401.今天正好朋友问怎么爆破,也顺便记录一下 怕忘记了 referer:http://www.2cto.com/Article/201303/194449.html 看到Burpsu ...
- HTTP使用BASIC认证的原理及实现方法
一. BASIC认证概述 在HTTP协议进行通信的过程中,HTTP协议定义了基本认证过程以允许HTTP服务器对WEB浏览器进行用户身份证的方法,当一个客户端向HTTP服务器进行数据请求时,如果客户 ...
随机推荐
- bWAPP----HTML Injection - Reflected (GET)
HTML Injection - Reflected (GET) 进入界面, html标签注入 这是核心代码 1 <div id="main"> 2 3 <h1& ...
- java的常用定时任务的几种方式
Java基本的定时任务,一般有这几种方式:一.Timer 1 public class Timer{ 2 static int index=0; 3 public static void main(S ...
- 这份java多线程笔记,你真得好好看看,我还没见过总结的这么全面的
1.线程,进程和多线程 1.程序:指指令和数据的有序集合,其本身没有任何意义,是一个静态的概念 2.进程:指执行程序的一次执行过程,是一个动态的概念.是系统资源分配的单位(注意:很多多线程是模拟出来的 ...
- 关于热力图的loss的一点感想
网络的输出的热力图和gt相减的差矩阵,求其最大特征值的平方作为loss. 若图像h w不相等,可以使用奇异值代替特征值.奇异值往往对应着矩阵中隐含的重要信息,且重要性和奇异值大小正相关.每个矩阵A都可 ...
- VS2019配置C+++mingW32配置
两个安装教程博客 http://t.sg.cn/yq22mn http://t.sg.cn/wsavo0 基于调试报错,是因为文件夹是中文,贴一个详细的博客:http://t.sg.cn/3j5e4z
- 【常见踩坑】】USB调试安装失败(Installation failed with message INSTALL_CANCELED_BY_USER)
[参考]http://www.cnblogs.com/liushilin/p/6553918.html 问题:在USB安装调试(小米手机),出现如下错误 解决:1.小米手机解决办法见参考.登录小米账号 ...
- 微服务架构下 CI/CD 如何落地
本文系云原生应用最佳实践杭州站活动演讲稿整理.杭州站活动邀请了 Apache APISIX 项目 VP 温铭.又拍云平台开发部高级工程师莫红波.蚂蚁金服技术专家王发康.有赞中间件开发工程师张超,分享云 ...
- moviepy音视频剪辑VideoClip类set_position方法pos参数的使用方法及作用
☞ ░ 前往老猿Python博文目录 ░ moviepy音视频剪辑VideoClip类set_position方法用于多个剪辑合成一个剪辑时设置调用剪辑实例的拷贝在合成剪辑的位置. 调用语法: set ...
- 第四十章、PyQt显示部件:QGraphicsView图形视图和QGraphicsScene图形场景简介及应用案例
专栏:Python基础教程目录 专栏:使用PyQt开发图形界面Python应用 专栏:PyQt入门学习 老猿Python博文目录 老猿学5G博文目录 一.概述 Designer中的Graphics V ...
- 为什么Python中称__lt__、__gt__等为“富比较”方法
Python中基类object提供了一系列可以用于实现同类对象进行"比较"的方法,可以用于同类对象的不同实例进行比较,包括__lt__.__gt__.__le__.__ge__._ ...