Druid是一个强大的新兴数据库连接池,兼容DBCP,是阿里巴巴做的开源项目.

不仅提供了强悍的数据源实现,还内置了一个比较靠谱的监控组件。 

GitHub项目主页: ​​https://github.com/alibaba/druid​

QQ群:  点击链接加入群【​​阿里开源技术交流​​】

常见问题回答请参考: ​​https://github.com/alibaba/druid/wiki/%E5%B8%B8%E8%A7%81%E9%97%AE%E9%A2%98​

​​

因为想要监控数据,又不愿意谁都可以访问,所以想要配置个密码.在开源群里一问,就知道原来内部已经有实现了.

先贴完成后的代码:

web.xml​ 部分:

<!-- Druid,监控数据库,以及WEB访问连接信息 -->
<!-- 参考: https://github.com/alibaba/druid/wiki/%E9%85%8D%E7%BD%AE_%E9%85%8D%E7%BD%AEWebStatFilter -->
<filter>
<filter-name>DruidWebStatFilter</filter-name>
<filter-class>com.alibaba.druid.support.http.WebStatFilter</filter-class>
<init-param>
<param-name>exclusions</param-name>
<param-value>*.js,*.gif,*.jpg,*.png,*.css,*.ico,*.jsp,/druid/*,/download/*</param-value>
</init-param>
<init-param>
<param-name>sessionStatMaxCount</param-name>
<param-value>2000</param-value>
</init-param>
<init-param>
<param-name>sessionStatEnable</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>principalSessionName</param-name>
<param-value>session_user_key</param-value>
</init-param>
<init-param>
<param-name>profileEnable</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>DruidWebStatFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- 配置 Druid 监控信息显示页面 -->
<servlet>
<servlet-name>DruidStatView</servlet-name>
<servlet-class>com.alibaba.druid.support.http.StatViewServlet</servlet-class>
<init-param>
<!-- 允许清空统计数据 -->
<param-name>resetEnable</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<!-- 用户名 -->
<param-name>loginUsername</param-name>
<param-value>druid</param-value>
</init-param>
<init-param>
<!-- 密码 -->
<param-name>loginPassword</param-name>
<param-value>druid</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>DruidStatView</servlet-name>
<url-pattern>/druid/*</url-pattern>
</servlet-mapping>


下面分享一下如何查找的。

首先,因为使用的是 MAVEN, 所以查看源码时maven会自动帮你下载. 我们在 web.xml 中点击 ​com.alibaba.druid.support.http.StatViewServlet​ 进入class文件,等一会源码下载好就可以查看. 发现有类似下面这样的代码: 

public class StatViewServlet extends ResourceSerlvet {

private final static Log LOG = LogFactory.getLog(StatViewServlet.class);

private static final long serialVersionUID = 1L;

public static final String PARAM_NAME_RESET_ENABLE = "resetEnable";

public static final String PARAM_NAME_JMX_URL = "jmxUrl";
public static final String PARAM_NAME_JMX_USERNAME = "jmxUsername";
public static final String PARAM_NAME_JMX_PASSWORD = "jmxPassword";

private DruidStatService statService = DruidStatService.getInstance();

/** web.xml中配置的jmx的连接地址 */
private String jmxUrl = null;
/** web.xml中配置的jmx的用户名 */
private String jmxUsername = null;
/** web.xml中配置的jmx的密码 */
private String jmxPassword = null;
.........


可以看出,继承了

StatViewServlet ​extends

ResourceSerlvet

而在其中的 jmxUrl、jmxUsername 和 jmxPassword 很显然是连接远程 JMX时使用的,那么我就想着去看看父类: ​com.alibaba.druid.support.http.ResourceSerlvet

@SuppressWarnings("serial")
public abstract class ResourceSerlvet extends HttpServlet {

private final static Log LOG = LogFactory.getLog(ResourceSerlvet.class);

public static final String SESSION_USER_KEY = "druid-user";
public static final String PARAM_NAME_USERNAME = "loginUsername";
public static final String PARAM_NAME_PASSWORD = "loginPassword";
public static final String PARAM_NAME_ALLOW = "allow";
public static final String PARAM_NAME_DENY = "deny";
public static final String PARAM_REMOTE_ADDR = "remoteAddress";

protected String username = null;
protected String password = null;
..........


看到了 username 和 password,很高兴,先配置了试试,但是配置这两个初始化参数后没起作用,于是继续查找. 看到了 service方法,我们知道,Servlet的业务逻辑就是从这里开始的。

public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
......
if (isRequireAuth() //
&& !ContainsUser(request)//
&& !("/login.html".equals(path) //
|| path.startsWith("/css")//
|| path.startsWith("/js") //
|| path.startsWith("/img"))) {
if (contextPath == null || contextPath.equals("") || contextPath.equals("/")) {
response.sendRedirect("/druid/login.html");
} else {
if ("".equals(path)) {
response.sendRedirect("druid/login.html");
} else {
response.sendRedirect("login.html");
}
}
return;
}
......


发现调用了  

isRequireAuth()​ 方法,看着像是判断是否需要授权验证,于是进去看

public boolean isRequireAuth() {
return this.username != null;
}

那现在知道是 username 在作怪,也设置了,但是没有起作用,于是搜索 username ,

public void init() throws ServletException {
initAuthEnv();
}

private void initAuthEnv() {
String paramUserName = getInitParameter(PARAM_NAME_USERNAME);
if (!StringUtils.isEmpty(paramUserName)) {
this.username = paramUserName;
}

String paramPassword = getInitParameter(PARAM_NAME_PASSWORD);
if (!StringUtils.isEmpty(paramPassword)) {
this.password = paramPassword;
}
......

然后发现了初始化验证环境时使用了PARAM_NAME_USERNAME这个参数,顺便的学习了一个新API: getInitParameter 方法获取 Servlet的初始化参数, 是HttpServlet的父类 GenericServlet 类提供的:


String paramUserName = getInitParameter(PARAM_NAME_USERNAME);

那么很简单,找到

PARAM_NAME_USERNAME​ 即可:


public static final String PARAM_NAME_USERNAME = "loginUsername";
public static final String PARAM_NAME_PASSWORD = "loginPassword";

于是在 web.xml 中换上,OK,成功进行了拦截.


你也可以参考这里:  

​CNCounter项目的web.xml​