【SpringBoot 搜索系列】Solr 身份认证与授权更新异常解决方案

10 阅读 作者:一灰灰blog 2020-10-20

之前介绍 solr 的教程中,solr 没有开启权限校验,所有的操作都是无需鉴权;当时提到,如果 solr 开启了权限校验,改一下 solr 的 host,带上用户名/密码即可,然而真实情况却并不太一样,查询 ok,涉及到修改的操作,则会抛异常

本文将带你了解一下,这到底是个什么鬼畜现象

I. Solr 配置用户登录

1. 安装

之前的 solr 系列教程中,通过 docker 安装的 solr,下面的步骤也是直接针对 docker 中的 solr 进行配置,基本步骤一样

不想看的同学,直接用下面的命令即可:

docker pull solr
docker run --name my-solr -d -p 8983:8983 -t solr

2. 配置

下面一步一步教你如何设置用户密码

进入实例,注意使用root用户,否则某些操作可能没有权限

docker exec  -u root -it my-solr /bin/bash

创建鉴权文件

vim server/etc/verify.properties

内容如下,格式为 用户名:密码,权限, 一行一个账号

root:123,admin

配置鉴权文件

vim server/contexts/solr-jetty-context.xml

添加下面的内容放在Configure标签内

<Get name="securityHandler">
   <Set name="loginService">
           <New class="org.eclipse.jetty.security.HashLoginService">
                  <Set name="name">verify—name</Set>
                  <Set name="config"><SystemProperty name="jetty.home" default="."/>/etc/verify.properties</Set>
           </New>
   </Set>
</Get>

修改 web.xml

vim server/solr-webapp/webapp/WEB-INF/web.xml

security-constraint标签下面,新增

<login-config>
		<auth-method>BASIC</auth-method>
		<!-- 请注意,这个name 和上面的Set标签中的name保持一致 -->
		<realm-name>verify-name</realm-name>
</login-config>

重启 solr,配置生效

docker restart my-solr

II. 场景复现

接下来介绍一下我们的环境

  • springboot: 2.2.1.RELEASE
  • solr: 8.0

1. 项目环境

搭建一个简单的 springboot 项目,xml 依赖如下

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.2.1.RELEASE</version>
    <relativePath/> <!-- lookup parent from repository -->
</parent>

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    <java.version>1.8</java.version>
</properties>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-solr</artifactId>
    </dependency>

    <!-- 请注意,在solr开启登录验证时,这个依赖必须有 -->
    <dependency>
        <groupId>commons-codec</groupId>
        <artifactId>commons-codec</artifactId>
    </dependency>
</dependencies>

<build>
    <pluginManagement>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </pluginManagement>
</build>
<repositories>
    <repository>
        <id>spring-snapshots</id>
        <name>Spring Snapshots</name>
        <url>https://repo.spring.io/libs-snapshot-local</url>
        <snapshots>
            <enabled>true</enabled>
        </snapshots>
    </repository>
    <repository>
        <id>spring-milestones</id>
        <name>Spring Milestones</name>
        <url>https://repo.spring.io/libs-milestone-local</url>
        <snapshots>
            <enabled>false</enabled>
        </snapshots>
    </repository>
    <repository>
        <id>spring-releases</id>
        <name>Spring Releases</name>
        <url>https://repo.spring.io/libs-release-local</url>
        <snapshots>
            <enabled>false</enabled>
        </snapshots>
    </repository>
</repositories>

对应的配置文件application.yml

spring:
  data:
    solr:
      # 请注意,用户名密码直接写在了url中
      host: http://root:123@127.0.0.1:8983/solr

2. 复现

关于 solr 的基本操作,如果有疑问的小伙伴可以翻一下我之前的搜索系列博文,满足你的扫盲需求;

核心的 solr 操作实例如下:

@Data
public class DocDO implements Serializable {
    private static final long serialVersionUID = 7245059137561820707L;
    @Id
    @Field("id")
    private Integer id;
    @Field("content_id")
    private Integer contentId;
    @Field("title")
    private String title;
    @Field("content")
    private String content;
    @Field("type")
    private Integer type;
    @Field("create_at")
    private Long createAt;
    @Field("publish_at")
    private Long publishAt;
}

@Component
public class SolrOperater {

    @Autowired
    private SolrTemplate solrTemplate;


    public void operate() {
        testAddByDoc();
        queryById();
    }

    public void testAddByDoc() {
        SolrInputDocument document = new SolrInputDocument();
        document.addField("id", 999999);
        document.addField("content_id", 3);
        document.addField("title", "testAddByDoc!");
        document.addField("content", "新增哒哒哒");
        document.addField("type", 2);
        document.addField("create_at", System.currentTimeMillis() / 1000);
        document.addField("publish_at", System.currentTimeMillis() / 1000);

        UpdateResponse response = solrTemplate.saveDocument("yhh", document, Duration.ZERO);
        solrTemplate.commit("yhh");
        System.out.println("over:" + response);
    }

    private void queryById() {
        DocDO ans = solrTemplate.getById("yhh", 999999, DocDO.class).get();
        System.out.println("queryById: " + ans);
    }
}

SolrTemplat定义如下

@Configuration
public class SearchAutoConfig {
    @Bean
    @ConditionalOnMissingBean(SolrTemplate.class)
    public SolrTemplate solrTemplate(SolrClient solrClient) {
        return new SolrTemplate(solrClient);
    }
}

开始测试

@SpringBootApplication
public class Application {

    public Application(SolrOperater solrOperater) {
        solrOperater.operate();
    }

    public static void main(String[] args) {
        SpringApplication.run(Application.class);
    }
}

请注意,复现上面的场景时,会发现查询没问题,修改则会抛异常

3. 解决方案

a. 降版本

我之前用 solr 的时候,也是上面的操作方式,然而并没有出现过这种问题,这就有点蛋疼了;

找之前的项目查看版本,发现之前用的solr-solrj用的是6.6.5,换个版本试一下(默认的版本是8.2.0

<dependency>
    <groupId>org.apache.solr</groupId>
    <artifactId>solr-solrj</artifactId>
    <version>6.6.5</version>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-solr</artifactId>
    <exclusions>
        <exclusion>
            <groupId>org.apache.solr</groupId>
            <artifactId>solr-solrj</artifactId>
        </exclusion>
    </exclusions>
</dependency>

见证奇迹的时刻到了,执行正常了,虽然saveDocument方法的调用标红,但是不影响具体的执行哦

b. SystemDefaultHttpClient

通过一顿 debug,单步执行,终于找到为啥6.6.5版本的solr-solrj可以正常操作,而8.2.0却不行(如果想知道这一枯燥的过程,请评论告诉我,否则我也不知道啥时候可以看到

原文地址:https://www.imooc.com/article/302759
广告一下
热门教程
PHP7报A non well formed numeric value encountered 0
Linux系统下关闭mongodb的几种命令分享 0
mongodb删除数据、删除集合、删除数据库的命令 0
Git&Github极速入门与攻坚实战课程 0
python爬虫教程使用Django和scrapy实现 0
libnetsnmpmibs.so.31: cannot open shared object file 0
数据结构和算法视频教程 0
redis的hash结构怎么删除数据呢? 0
C++和LUA解析器的数据交互实战视频 0
mongodb errmsg" : "too many users are authenticated 0
C++基础入门视频教程 0
用30个小时精通C++视频教程可能吗? 0
C++分布式多线程游戏服务器开发视频教程socket tcp boost库 0
C++培训教程就业班教程 0
layui的util工具格式时间戳为字符串 0
C++实战教程之远程桌面远程控制实战 1
网络安全培训视频教程 0
LINUX_C++软件工程师视频教程高级项目实战 0
C++高级数据结构与算法视频教程 0
跨域问题很头疼?通过配置nginx轻松解决ajax跨域问题 0
相关文章
【译】JavaScript数据结构(3):单向链表与双向链表 16
10个JavaScript难点 16
【译】苹果拒绝支持PWA,有损Web的未来 16
iView 一周年了,同时发布了 2.0 正式版,但这只是开始... 16
nodejs+mongodb构建一个简单登录注册功能 16
【译】JavaScript数据结构(4):树 16
组件化开发与黑箱 16
TypeScript - 不止稳,而且快 16
webpack3+anujs+ReactCSSTransitionGroup 16
原生js实现图片放大镜效果 16
WEB缓存探究第二弹——实战 16
纯笔记:vfork 的一些使用场景(顺便讲一下 fork 的原理) 16
Android APP 内部捐赠实现(支付宝&amp;微信) 16
WKWebView 的一些小总结 16
模型评价(一) AUC大法 16
开始使用GraphQL 16
Webpack模块化原理简析 16
gulp使用问题记录 16
使用Angular4动画为页面添彩 16
Python27 Matplotlib (win64 python2.7) 安装及简单使用 16