Shiro实现Basic认证

王子已经有了一套集成好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 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测试一下
亚马逊测评 www.yisuping.com

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值