为Druid监控配置访问权限(配置访问监控信息的用户与密码)

时间:2022-02-21 09:58:14

转:

l

为Druid监控配置访问权限(配置访问监控信息的用户与密码)
2014-09-26 09:21:48         来源:renfufei的专栏  
收藏   我要投稿

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

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

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

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

演示地址: https://cncounter.duapp.com/druid/index.html

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

一篇CSDN对Druid的介绍 druid简单教程

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

先贴完成后的代码:

web.xml 部分:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
<!-- Druid,监控数据库,以及WEB访问连接信息 -->
<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文件,等一会源码下载好就可以查看. 发现有类似下面这样的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@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;
.......... 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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() 方法,看着像是判断是否需要授权验证,于是进去看

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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,成功进行了拦截.