发表于: 2019-11-12 20:35:40
1 1066
今天完成的事情:
Servlet 过滤器可以动态地拦截请求和响应,以变换或使用包含在请求或响应中的信息。
可以将一个或多个 Servlet 过滤器附加到一个 Servlet 或一组 Servlet。Servlet 过滤器也可以附加到JSP文件和 HTML 页面。
Servlet 过滤器是可用于 Servlet 编程的 Java 类,可以实现以下目的:
在客户端的请求访问后端资源之前,拦截这些请求。
在服务器的响应发送回客户端之前,处理这些响应。
过滤器原理:
Filter接口中有一个doFilter方法,当我们编写好Filter,并配置对哪个web资源进行拦截后,WEB服务器每次在调用web资源的service方法之前,调用目标资源之前,让一段代码执行。
是否调用目标资源(即是否让用户访问web资源)。
web服务器在调用doFilter方法时,会传递一个filterChain对象进来,filterChain对象是filter接口中最重要的一个对象,它也提供了一个doFilter方法,开发人员可以根据需求决定是否调用此方法,调用该方法,则web服务器就会调用web资源的service方法,即web资源就会被访问,否则web资源不会被访问。
init(FilterConfig var1): web应用程序启动时,web服务器将创建Filter的实例对象,并调用其init方法,完成对象的初始化功能,从而为后续的用户请求作好拦截的准备工作,filter对象只会创建一次,init方法也只会执行一次。
doFilter(ServletRequest var1, ServletResponse var2, FilterChain var3):当有人访问web服务器时对请求进行操作。
destroy()web容器调用destroy方法销毁Filter。destroy方法在Filter的生命周期中仅执行一次。在destroy方法中,可以释放过滤器使用的资源。
public class LogFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
//获得初始化参数
String site = filterConfig.getInitParameter("Site");
//输出初始化参数
System.out.println("网站名称:"+site);
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
//把请求传回过滤链
filterChain.doFilter(servletRequest,servletResponse);
}
@Override
public void destroy() {
/* 在 Filter 实例被 Web 容器从服务移除之前调用 */
}
}
web.xml
<filter>
<filter-name>LogFilter</filter-name>
<filter-class>com.pojo.LogFilter</filter-class>
</filter>
<!--元素用于设置一个 Filter 所负责拦截的资源。一个Filter拦截的资源可通过两种方式来指定:Servlet 名称和资源访问的请求路径-->
<filter-mapping>
<!--子元素用于设置filter的注册名称。该值必须是在<filter>元素中声明过的过滤器的名字-->
<filter-name>LogFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
继续修改controller
@Controller
public class UserController {
private static Logger logger = Logger.getLogger(UserController.class);
@Autowired
UserService userService;
/**
* 跳转页面
* @return
*/
@RequestMapping(value = "/u/register", method = RequestMethod.GET)
public String register() {
return "register";
}
@RequestMapping(value = "/register", method = RequestMethod.POST)
public String insert(User user, HttpServletResponse response) throws UnsupportedEncodingException {
logger.info("新注册用户信息:" + user);
//对传进来的参数进行判空
if (!ObjectUtils.isEmpty(user.getName()) && !ObjectUtils.isEmpty(user.getPwd())) {
//通过用户名查找数据,看是否有这条数据
List<User> userName = userService.selectByName(user.getName());
//能查出来这条数据就说明数据库里有这条数据,那么注册失败,否则注册成功,跳转到首页
logger.info("userName:" + userName);
if (ObjectUtils.isEmpty(userName)) {
//插入时,使用MD5给密码加盐
user.setPwd(Md5Util.MD5(user.getPwd() + user.getId()));
logger.info("加密后的密码:" + user);
int x = userService.insert(user);
logger.info("userId:" + user.getId());
List<User> user1 = userService.selectByNameAndPwd(user.getName(), user.getPwd());
String token = DesUtil.encrypt(System.currentTimeMillis() + "|" + user.getName() + "|" + user.getId());
logger.info("token:" + token);
Cookie cookie = new Cookie("token", token);
cookie.setMaxAge(60 * 60);
logger.info("tokenName:" + cookie.getName());
logger.info("tokenValue:" + cookie.getValue());
response.addCookie(cookie);
return "home";
}
logger.info("用户名已存在");
return "redirect:/u/register";
}
logger.info("密码不能为空");
return "redirect:/u/register";
}
@RequestMapping(value ="/u/login",method = RequestMethod.GET)
public String loginIn(){
return "login";
}
@RequestMapping(value = "/login", method = RequestMethod.GET)
public String login(User user, HttpServletResponse response) throws UnsupportedEncodingException {
if (!ObjectUtils.isEmpty(user.getName()) && !ObjectUtils.isEmpty(user.getPwd())) {
//密码加密加盐,然后用密码和用户名与数据库里的数据对比
user.setPwd(Md5Util.MD5(user.getPwd() + user.getId()));
//加盐之后对比一下传进来的和数据库里的是否一致
List<User> user1 = userService.selectByNameAndPwd(user.getName(), user.getPwd());
if (!ObjectUtils.isEmpty(user1)) {
logger.info("查出的数据:" + user1);
//token由用户名,id,登录时间组成
String token = DesUtil.encrypt(System.currentTimeMillis() + "|" + user.getName() + "|" + user.getId());
logger.info("token:" + token);
Cookie cookie = new Cookie("token", token);
//设置过期时间,单位为秒
cookie.setMaxAge(60 * 60);
logger.info("tokenName=========" + cookie.getName());
logger.info("tokenValue============" + cookie.getValue());
response.addCookie(cookie);
return "home";
} else {
logger.info("没有找到该用户");
return "/register";
}
}
logger.info("账号密码错误");
return "/login";
}
@RequestMapping(value = "/logout", method = RequestMethod.GET)
public String logout(HttpServletResponse response, HttpServletRequest request) {
Cookie[] cookies = request.getCookies();
for (Cookie cookie : cookies) {
if ("token".equals(cookie.getName())) {
cookie.setMaxAge(0);
logger.info("被删除的token:" + cookie.getName());
response.addCookie(cookie);
return "home";
}
}
return "home";
}
}
明天计划的事情:
学习使用JWT代替token
遇到的问题:解决了空指针异常的问题
使用tag标签转换时间的工具类有点问题,对比了师兄的发现只有一点区别,把师兄的拿过来用了
收获:
什么是JWT
JWTjson web token
是为了在网络应用环境中传递声明而执行的一种基于json的开放标准。特别适合分布式站点的单点登录场景。jwt的声明一般被用来在身份提供者和服务提供者之间传递被认证的用户身份信息,以便于从服务器获取资源,也可以增加一些额外的其他业务逻辑所用到的生命信息。
jwt是由3段信息构成的,将这三段信息用.链接到一起就成了jwt字符串。
构成
第一部分称之为头部,第二部分称之为载荷,第三部分是签证。
header
头部承担两部分信息:
声明类型 jwt
加密算法 HMAC SHA256等
完整的头部:
将头部进行base64加密,构成了第一部分
playload
载荷就是存放有效信息的地方,包含三部分
- 标准中注册的声明
- 公共的声明
- 私有的声明
标准中注册的声明 (建议但不强制使用) :
iss: jwt签发者
sub: jwt所面向的用户
aud: 接收jwt的一方
exp: jwt的过期时间,这个过期时间必须要大于签发时间
nbf: 定义在什么时间之前,该jwt都是不可用的.
iat: jwt的签发时间
jti: jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击。
公共的声明:
公共的声明可以添加任何的信息,一般添加用户的相关信息或其他业务需要的必要信息.但不建议添加敏感信息,因为该部分在客户端可解密
私有的声明:
私有声明是提供者和消费者所共同定义的声明,一般不建议存放敏感信息,因为base64是对称解密的,意味着该部分信息可以归类为明文信息。
signature
jwt的第三部分是一个签证信息,这个签证信息由三部分组成:
header (base64后的)
payload (base64后的)
secret
这个部分需要base64加密后的header和base64加密后的payload使用.连接组成的字符串, 然后通过header中声明的加密方式进行加盐secret组合加密,然后就构成了jwt的第三部分。
评论