WEB开发之如何实现认证与授权(二)

WEB开发之如何实现认证与授权 (beta)

框架产生的目标是帮助开发人员解决一些特定场景下的通用问题,为一类问题提供一套有效的、稳定的解决方案,让程序员将主要精力放在业务逻辑的开发上。
没有一个框架能解决所有的问题,但我们可以通过对框架的理解来解决我们自身的业务问题,所以去理解框架的实现原理或者其进化过程,让我们有能力定制一些想要的功能。

在网上大部分文章都是教我们怎么去使用一门技术;极少人会取了解为什么这样做,本身在技术发展过程中,太多的底层原理被高度聚合,我们丢弃了很多技术演变的历史过程,这个无疑为我们的学习增添了难度。

要素

WEB安全框架的几个要素:

  • 主体
    携带认证信息的主体,可以是真实用户、一个APP客户端等等。包含了用户基本信息,角色,权限等,贯穿整个上下文中,为资源访问与操作提供检查与支持。

  • 客户端
    浏览器、移动端App、程序。不同类型的代理在实现认证技术上会有所差异,比如移动端没办法通过Cookie/Session机制去实现认证状态的保持。

  • 服务器资源
    应用页面、提供数据交换的API。认证与鉴权主要是针对资源,最常见的即是URL,我们更多关注的是URL的请求而非返回,当然像Spring Security亦可根据返回值决定鉴权是否成功。

  • 认证
    校验用户的身份,在web环境中基本上都是基于Filter实现,资源既然是URL,那么基于Servlet开发的Web容器无疑是最佳的选择。

  • 授权
    校验用户是否有访问资源的权限,基于Filter、AOP实现。如果粗粒度的控制资源的受限访问,Filter足够应对;但AOP可以在方法、参数上在数据实例上进行权限控制。一般系统中,最常见的也就是对资源的访问权限(查看)和操作权限(删除、修改)。

主体

身份认证对象。不一定是一个用户,可以是一个客户端、一个终端,一个程序,任何与系统交互的事务都可以看做是一个主体。

  • 在 Apache Shrio中是用Subject来表示,其包含了用户的身份,是否认证成功以及是否需要某种权限。
  • 而在Spring Security中,则是Authentication接口,通过该接口可以获取身份、凭证、角色权限信息以及其他扩展信息。

主体是一个抽象的概念,因此都被设计成接口,在不同的运行环境下会有不同的表现与关注点。在认证阶段我们仅需判断是否能够在上下文中拿到一个已认证的主体。在鉴权阶段则需要判断该主体是否具备有某个角色或权限。

	public interface Identity{
	
		Object getPrincipal();
		
		boolean isAuthed();
		
		boolean hasRole(String roleId);
		
		boolean hasPermission(String permission);
	}

代理

在PC端我们一般通过浏览器来访问我们的web应用,浏览器帮助我们实现资源的请求与响应。每一个资源的请求都是基于Http协议完成,要知道Http是一个应用层无状态通信协议,我们不需要每次请求资源时都进行重复的用户认证工作,在第一次用户认证成功后,通过浏览器保存此次交易的Cookie,与服务器Session结合实现用户与应用的持续会话。

	public interface SessionManager{
	
		Session getSession(String sessionKey);
	
	}

在MVC模式下,基于Cookie/Session无疑是比较简单的策略,然而在当下比较流行的形式是将前端页面与后端服务进行分离,页面调用后台服务时都是基于api实现,此时cookie已经失效,一般都会基于一串加密的token字符串进行实现身份的重复认证,只不过token包含过多的信息,比如用户的身份,过期时间等。

资源

资源即是Web应用提供对外的交互数据,可以是一个页面,一组json数据,一个文件等等,在主体访问资源时,首先需要确定当前用户是否已经认证通过;其次检验用户是否有权访问该资源;

认证失败异常:

	public abstract class AuthenticationException{
	
	}

拒绝访问异常:

	public abstract class AccessDeniedException{
	
	}

认证

前面说到,认证一般基于过滤器实现,在用户访问资源之前,通过过滤器判断用户是否已经认证

	public class AuthFilter extends AbstractFilter{
	
	}

认证成功后基于session自动构建主体对象,自动完成认证。

	public class SessionContextFilter extends AbstractFilter{
	
	}

系统登出Filter

	public class LogoutFilter extends AbstractFilter{
	
	}

鉴权

基于Filter或AOP实现,相比而言,基于Filter局限于请求或交易,如果系统运行在基于Servlet的Web容器中则可以通过过滤器实现;而基于动态代理的AOP则可以对方法间的调用,更加的通用。

	public class AuthInterceptFilter extends AbstractFilter{
	
	}

实现

流程

根据上面的理解简单地实现了一个版本,部分功能仅仅做作为示意,在实现与高可用上仅作为参考使用,具体代码没有张贴,github地址

https://github.com/sucls/auth-sample

结束语

编写示例一是为了验证自己的思路,其次在后面阅读源码的过程中,可以有目的的思考,很多框架的实现都是从大的构思到细节的完善,只不过在细节处理上更加的严谨,同时考虑到稳定性、易用性、扩展性等问题,不得不在实现上做很多取舍,最终呈现的代码量都会非常大,但是能够抓住核心思想,在理解框架本身,也是提升自己更好的方式。

后面会以应用为出发点,从功能、实现以及源码层面逐步将主流的安全认证框架逐步呈现。

posted @ 2022-06-28 19:17  Cycads  阅读(415)  评论(0)    收藏  举报