一、权限验证
要修改用户资料首先需要用户登录,有两种方法进行权限验证
Servlet
的过滤器 Filter
package com.bookstore.Filter;
import com.bookstore.Domain.User;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
@WebFilter(urlPatterns = {"/myAccount"}) //到底要不要加@Component,不加也能工作
public class RequiredLoginFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
try {
User user = (User) req.getSession().getAttribute("user"); //对null强转也不会出错
System.out.println("RequiredLoging filter working" + user);
if(user == null)throw new ClassCastException();
chain.doFilter(req, response);
} catch (ClassCastException e) {
String returnURL = request.getMethod().equalsIgnoreCase("POST") ? request.getHeader("Referer") : request.getRequestURL().toString(); //根据方法不同选择不同跳转地址
req.setAttribute("message", "您还未登录#登录页面#login?returnURL=" + returnURL); //方便在登录后跳转回原页面,还需相应改动login的handler部分,请参考前文
req.getRequestDispatcher("/WEB-INF/views/message.jsp").forward(req, response);
}
}
}
Spring MVC
的拦截器 Interceptor
package com.bookstore.Interceptor;
import com.bookstore.Domain.User;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class RequiredLoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
User user = (User) request.getSession().getAttribute("user");
if(user == null){
String returnURL = request.getMethod().equalsIgnoreCase("POST") ? request.getHeader("Referer") : request.getRequestURL().toString();
request.setAttribute("message", "您还未登录#登录页面#login?returnURL=" + returnURL); //方便在登录后跳转回原页面,还需相应改动login的handler部分,请参考前文
request.getRequestDispatcher("/WEB-INF/views/message.jsp").forward(request,response); //以contextroot为根目录
return false; //我挺好奇的不加这个跳转后怎么执行
}
return true;
}
}
使用拦截器还需要在SpringMVC的配置文件添加设置
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/myAccount"/>
<bean class="com.bookstore.Interceptor.RequiredLoginInterceptor" />
</mvc:interceptor>
</mvc:interceptors>
二、修改用户资料实现代码
UserController.java
@GetMapping("/myaccount")
public String myAccount() {
return "myAccount";
}
@GetMapping("/modifyuserinfo")
public String modifyUserInfo() {
return "modifyuserinfo";
}
@InitBinder
public void disallowFileds(WebDataBinder binder) {
binder.setDisallowedFields("id", "activecode", "role", "state"); // 用于防范攻击,可以看看下面的发现,不知道还有没有更好的方法
}
@PostMapping("/modifyuserinfo")
public String modifyUserInfo(User modifiedUser, Model model, HttpSession session) throws UserException {
//修改资料
modifiedUser.setId(((User) session.getAttribute("user")).getId()); //通过initBinder禁止,即使没有设置攻击也不会成功
// modifiedUser.setUsername(((User) session.getAttribute("user")).getUsername());
userService.modifyUserInfo(modifiedUser);
//重载sesssion中的user信息
modifiedUser = userService.getUserByID(modifiedUser.getId());
session.setAttribute("user", modifiedUser);
model.addAttribute("message", "资料更新成功");
return "message";
}
UserService.java
@Transactional
public void modifyUserInfo(User modifiedUser) throws UserException {
int result = userDao.updateByPrimaryKeySelective(modifiedUser);
if(result != 1){
throw new UserException("资料更新失败#-1");
}
}
public User getUserByID(String id) {
return userDao.selectByPrimaryKey(id);
}
三、有趣发现
在不添加InitBinder
屏蔽部分字段时,通过修改表单可以强改信息
新注册一个用户
数据库在注册后如图所示
激活后修改资料
修改表单为下图所示,模拟攻击——利用工具修改了username并添加了id字段
MyBatis更新语句 —— 用户名强改成功,但id没有被修改
数据库中保存结果
注意比较——莫名其妙少了一天,搜索了下看起来与时区设置有关
补充下——用role字段来模拟攻击,可以看到其被initBinder给屏蔽了没有产生效果: