第一部分:访问控制
目的:防止非本系统用户通过http请求操作用户数据
方法:
1 当用户执行登录操作的时候,由前端生成token传到后台,后台将token以及该token的过期的时间存储在数据库
2 往后所有的api请求头内必须携带该token,否则该请求无效。如果请求中携带token则前去数据库检索该token的有效性及是否超时
实现:
@Component
//拦截所有路径
@WebFilter(urlPatterns = { "/**" }, filterName = "tokenAuthorFilter")
public class ConfigurationFilter implements Filter{
@Autowired
shiroService shiroService;
//定义不需要拦截的url
private static final Set ALLOWED_PATHS = Collections.unmodifiableSet(new HashSet<>(
Arrays.asList(
"webjars",
"druid",
"swagger",
"v2",
"swagger-ui.html",
"swagger-resources",
"configuration",
"images"
)
)
);
@Override
public void destroy() {
// TODO Auto-generated method stub
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletResponse responses = (HttpServletResponse) response;
HttpServletRequest requestes = (HttpServletRequest) request;
// 允许哪些Origin发起跨域请求,nginx下正常
// response.setHeader( "Access-Control-Allow-Origin", config.getInitParameter( "AccessControlAllowOrigin" ) );
responses.setHeader( "Access-Control-Allow-Origin", "*" );
// 允许请求的方法
responses.setHeader( "Access-Control-Allow-Methods", "POST,GET,OPTIONS,DELETE,PUT" );
// 多少秒内,不需要再发送预检验请求,可以缓存该结果
responses.setHeader( "Access-Control-Max-Age", "3600" );
// 表明它允许跨域请求包含xxx头
responses.setHeader( "Access-Control-Allow-Headers", "content-type,token" );
//是否允许浏览器携带用户身份信息(cookie)
if (requestes.getMethod().equals( "OPTIONS" )) {
responses.setStatus( 200 );
return;
}
//将不需要拦截的url过滤
String path = requestes.getRequestURI().substring(requestes.getContextPath().length()).replaceAll("[/]+$", "");
String paths[] =path.split("/");
boolean allowedPath = ALLOWED_PATHS.contains(paths[1]);
if (allowedPath) {
chain.doFilter(requestes, responses);
}
//获取token
String token=requestes.getHeader("Token");
//获取该token的用户信息
sysUserInfo uInfo= shiroService.queryByToken(token);
if(uInfo!=null){
chain.doFilter(requestes, responses);//到下一个链
}else{
responses.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
return;
}
}
@Override
public void init(FilterConfig arg0) throws ServletException {
// TODO Auto-generated method stub
}
}
权限控制
思路:仿照shior,给每个用户一个角色,每个角色拥有不同的权限,权限包括不同页面的查看以及不同表的增删改查
步骤: 1建表:分别建立角色表 用户表 页面表 角色与用户对应表
如上图所示,有一个用户名为123的用户角色id为1对应角色表里的角色是超级管理员,在角色与用户对应表中角色与用户对应表角色id1对应的超级管理员拥有页面表中id为12,13的操作权,在页面表中id 12 13分别对应的是列表页面的新增和查看
2新建注解用于方法中的权限控制
@Retention(RetentionPolicy.RUNTIME) // 表示注解在运行时依然存在
@Target(ElementType.METHOD)
@Documented
public @interface permission {
public String perm() default "";
}
**3 **在涉及到权限访问的方法上加上权限注解,我们在第一步中的列表查看接口上加上访问权限注解
@permission(perm = "meau/list")
@RequestMapping(value = "/list", method = RequestMethod.GET)
@ApiOperation("获取菜单列表")
public Map meauList(){
return meauService.getList();
}
}
4 核心自定义拦截器拦截有第三步定义的权限注解的方法,然后从请求头中获取token,通过token获取用户信息及该用户拥有的权限集合,如果不包括注解中的权限值则判断该用户没有对方法的访问权
@Component
public class MyInterceptor extends HandlerInterceptorAdapter{
@Autowired
private tokenDao tokenDao;
//在请求处理之前进行调用(Controller方法调用之前
@Override
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
//如果不是映射到方法直接通过
if (!(o instanceof HandlerMethod)) {
return true;
}
HandlerMethod handlerMethod = (HandlerMethod) o;
Method method = handlerMethod.getMethod();
if (method.getAnnotation(permission.class) != null) {
//获取拥有权限注解的方法中的权限值
permission permissionAnnotation=method.getAnnotation(permission.class);
String permStr = permissionAnnotation.perm();
//获取本次请求中所携带的token信息所属用户的权限列表
//获取token
String token=httpServletRequest.getHeader("Token");
//获取该token的用户信息的权限列表
List list= tokenDao.queryMeauByToken(token);
//如果该用户所属权限列表包含该权限值则正常请求
if(list.contains(permStr)){
return true;
}else{
httpServletResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
return false;
}
}else{
return true;
}
}
结果测试
从第一步的表中可知用户123的token值为99999999999999999999999999999999
当我们token带上99999999999999999999999999999999请求时
当token值不存在时访问
当用户123去除该方法的访问权限时访问