仿照shiro实现前后分离项目权限认证

第一部分:访问控制
目的:防止非本系统用户通过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建表:分别建立
角色表
用户表 页面表 角色与用户对应表
仿照shiro实现前后分离项目权限认证_第1张图片
仿照shiro实现前后分离项目权限认证_第2张图片
仿照shiro实现前后分离项目权限认证_第3张图片

仿照shiro实现前后分离项目权限认证_第4张图片

如上图所示,有一个用户名为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请求时
仿照shiro实现前后分离项目权限认证_第5张图片
当token值不存在时访问
仿照shiro实现前后分离项目权限认证_第6张图片
当用户123去除该方法的访问权限时访问
仿照shiro实现前后分离项目权限认证_第7张图片
仿照shiro实现前后分离项目权限认证_第8张图片

你可能感兴趣的:(java,java常用开发记录)