之前介绍 solr 的教程中,solr 没有开启权限校验,所有的操作都是无需鉴权;当时提到,如果 solr 开启了权限校验,改一下 solr 的 host,带上用户名/密码即可,然而真实情况却并不太一样,查询 ok,涉及到修改的操作,则会抛异常
本文将带你了解一下,这到底是个什么鬼畜现象
I. Solr 配置用户登录
1. 安装
之前的 solr 系列教程中,通过 docker 安装的 solr,下面的步骤也是直接针对 docker 中的 solr 进行配置,基本步骤一样
具体可以参考: 【搜索系列】Solr 环境搭建与简单测试
不想看的同学,直接用下面的命令即可:
docker pull solr
docker run --name my-solr -d -p 8983:8983 -t solr
2. 配置
下面一步一步教你如何设置用户密码,也可以参考博文: 手把手教你 对 solr8 配置用户登录验证
进入实例,注意使用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
却不行(如果想知道这一枯燥的过程,请评论告诉我,否则我也不知道啥时候可以看到