title: nginx实现用户行为监控 tags:
- elk
- shiro
- 用户行为
- cookie categories: nginx date: 2017-06-25 18:18:56
目前由于系统的安全要求以及后期一些溯源工作,需要对于请求记录下对应的访问者信息。
目前对于系统中较为简单的记录方式时保留用户名。
我们采取一种较为简单的方式,将用户名放入cookie中。
然后在nginx日志中解析对应的cookie获得登录人信息(目前确实无法避免别人仿照问题,后期考虑jwt)
目前采用shiro在登录时写入cookie 如下
package com.air.tqb.shiro.listener;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationListener;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.servlet.Cookie;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.apache.shiro.web.util.WebUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Created by qixiaobo on 2017/5/15.
*/
public class ShiroAuthenticationListener implements AuthenticationListener {
@Autowired
@Qualifier("userNameCookie")
private SimpleCookie template;
private Logger logger = LoggerFactory.getLogger(ShiroAuthenticationListener.class);
@Override
public void onSuccess(AuthenticationToken token, AuthenticationInfo info) {
Subject subject = SecurityUtils.getSubject();
HttpServletRequest request = WebUtils.getHttpRequest(subject);
HttpServletResponse response = WebUtils.getHttpResponse(subject);
Cookie cookie = new SimpleCookie(template);
cookie.setValue(String.valueOf(token.getPrincipal()));
cookie.saveTo(request, response);
logger.info("{} login success", token.getPrincipal());
}
@Override
public void onFailure(AuthenticationToken token, AuthenticationException ae) {
logger.info("{} logout failed!", token.getPrincipal());
}
@Override
public void onLogout(PrincipalCollection principals) {
Subject subject = SecurityUtils.getSubject();
HttpServletRequest request = WebUtils.getHttpRequest(subject);
HttpServletResponse response = WebUtils.getHttpResponse(subject);
Cookie cookie = new SimpleCookie(template);
cookie.setMaxAge(0);
cookie.saveTo(request, response);
logger.info("{} logout success", principals);
}
}
复制代码
<!-- Shiro导入 Begin-->
<!-- 配置securityManager -->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="cacheManager" ref="cacheManagerShiro"/>
<property name="sessionManager" ref="sessionManager"/>
<property name="realm" ref="jdbcRealm"/>
<property name="authenticator.authenticationListeners">
<list>
<bean class="com.air.tqb.shiro.listener.ShiroAuthenticationListener"/>
<bean class="com.air.tqb.shiro.listener.KickOutSessionListener">
<property name="sessionManager" ref="sessionManager"/>
<property name="kickoutAfter" value="false"/>
<property name="maxSession" value="1"/>
</bean>
</list>
</property>
</bean>
<bean id="userNameCookie" class="org.apache.shiro.web.servlet.SimpleCookie">
<constructor-arg value="un"/>
<property name="httpOnly" value="true"/>
<property name="maxAge" value="-1"/>
</bean>
复制代码
对于回调listener配置ShiroAuthenticationListener 对应注入的cookie使用名称为un的cookie(名称尽量短,减少流量)
在nginx中配置
server {
listen 80;
server_name yunxiu.f6car.com;
set $un "$remote_user";
if ( $http_cookie ~* ".*un=([^;]*)(?:;|$)" ){
set $un $1;
}
access_log logs/access_nginx_yunxiu.log yunxiu;
log_format yunxiu '$remote_addr - $un [$time_local] $http_host $request_method "$uri" '
'$status $body_bytes_sent "$http_referer" $upstream_status "$upstream_addr" $request_time $upstream_response_time '
'"$http_user_agent" "$http_cdn_src_ip" "$http_x_forwarded_for" "$query_string"' ;
复制代码