如何快速实现SpringSecutity登录认证以及权限验证?!

   在开始之前,让我们先看下security运行的基本原理,理清一下思路,理清思路不管在我们开发什么项目、在任何项目阶段,都是至关重要的 。

 

目标
在原公司有专门的登录验证和权限管理服务,换公司后在最近项目中需要使用Spring Security自主实现分布式系统的用户验证授权及权限验证功能,因此花了两天时间研究并实现了该方案: 
功能点细分: 
1. 基于REST请求的登录 
2. 用户名密码验证及验证成功后给用户授权 
3. http请求的权限配置和验证 
4. 方法级别的权限配置和验证 
5. 分布式环境中用户权限共享

分析及实现
一、基于REST请求的登录
1.1 分析
Spring Security默认是通过表单提交用户登录请求,可通过修改配置实现自定义登录请求

1.2 实现
在spring-security.xml中配置如下为自定义的登录入口,并在entry-point-ref中配置登录url(只需关注红框标注部分) 

注:中别的配置将在下文中分别介绍

二、用户名密码验证及验证成功后给用户授权
2.1 分析
Spring Security的底层是通过一系列Filter管理的,当我们使用NameSpace时,Spring Security会自动创建FilterChain及默认包含的Filter。其中几个关键Filter的位置和作用如下,完整信息可参考(http://wiki.jikexueyuan.com/project/spring-security/filter.html)

 

过滤器位置作用
SecurityContextPersistenceFilterSECURITY_CONTEXT_FILTER进行 request 时在 SecurityContextHolder 中建立一个 SecurityContext
UsernamePasswordAuthenticationFilterFORM_LOGIN_FILTER
认证及授权处理, 为SecurityContextHolder添加一个有效的 Authentication
FilterSecurityInterceptorSECURITY_CONTEXT_FILTER

 保护 Http 资源,判断用户是否有权限访问相应的资源


 

由此可见该功能点是通过UsernamePasswordAuthenticationFilter实现的。UsernamePasswordAuthenticationFilter会调用AuthenticationManager处理认证请求的接口。AuthenticationManager又会进一步把该请求委托给AuthenticationProvider处理。AuthenticationProvider会根据请求的用户名调用UserDetailsService获取用户详情UserDetails。Spring Security有内置UserDetailsService实现,如:

CachingUserDetailsService从缓存中加载用户详情
JdbcDaoImpl从数据库中加载用户详情
InMemoryUserDetailsManager从内存中加载用户详情
这些均不能满足当前系统的需求,我们需要调用系统中用户服务的接口来加载用户详情,所以这里需要定义自己的UserDetailsService实现。

2.2 实现
(1) 自定义UserInfoService实现UserDetailsService接口,重写其loadUserByUsername()方法实现从用户服务的接口来加载用户详情 


(2) 在spring-security.xml中配置UsernamePasswordAuthenticationFilter实例authenticationFilter,并为其逐级注入自定义的UserDetailsService实例userInfoService。 


(3) 用authenticationFilter替换FilterChain中默认的认证过滤器UsernamePasswordAuthenticationFilter 

之前介绍过FilterChain中的默认的Filter都有自己的位置,UsernamePasswordAuthenticationFilter 对应的位置为FORM_LOGIN_FILTER。Spring Security支持通过 position、before 或者 after 指定自定义 Filter放置的位置。红框中语句的含义就是将authenticationFilter放置到FORM_LOGIN_FILTER位置,也就实现了替换默认UsernamePasswordAuthenticationFilter的功能

(4) 整个用户认证及授权的流程如下: 


 
  注:红框部分“分布式环境中用户权限共享”功能的部分实现,后面介绍

三、HTTP请求的权限配置和验证
3.1 分析
HTTP请求的权限配置就是自定义url和所需权限的对应关系。在配置文件中实现 
HTTP请求的权限验证就是检查用户登录授权阶段获取到的用户权限是否可以访问该url。Spring Security中FilterSecurityInterceptor通过调用AccessDecisonManager的相应接口完成权限认证,其中AccessDecisonManager或配置一个或多个AccessDecisionVoter的vote()方法来进行投票(成功返回1,失败返回-1),并根据每个AccessDecisionVoter的投票结果及一定的策略决定该用户是否有权限访问该url。Spring Security默认使用的AccessDecisonManager实现类AffirmativeBased的策略是只要有一个AccessDecisionVoter投了反对票(即vote方法返回-1),则拒绝访问url。Spring Security中也有多个AccessDecisionVoter实现类,这里介绍两个常用的AccessDecisionVoter:

WebExpressionVoter 基于表达式匹配的投票方法,即只要用户权限中包含url所需的权限即投赞成票
RoleVoter 类似于WebExpressionVoter但是需要配置权限前缀,默认前缀为ROLE_
3.2 实现
(1) 在spring-security.xml中配置url及其权限的对应关系 

红框语句的含义就是为能匹配“/dicts**”表达式的url请求配置ROLE_DICT权限

(2) 权限检查的过滤器FilterSecurityInterceptor及其配置均使用Spring Security默认配置。

(3) 一次非登录的Http请求的完整流程如下: 

注:红框部分“分布式环境中用户权限共享”功能的部分实现,后面介绍

四、方法级别的权限配置和验证
4.1 分析
可基于注解实现,参考http://blog.csdn.net/w605283073/article/details/51327182

4.2 实现
(1) 在spring-security.xml中开启@PreAuthorize的注解支持 
 
(2) 为需要权限验证的方法添加@PreAuthorize注解

五、分布式环境中用户权限共享
5.1 分析
当前分布式系统已经实现了基于Redis的分布式Session,也即同一次访问过程中经过不同主机上不同服务之间是共享Session的。因此当我们需要实现用户权限共享时,只需要在登录验证阶段获取到的用户详情信息(包含用户权限)写入到Session中即可。通过上一节的“用户认证及授权的流程”中可知用户完成验证后的用户详情信息会封装为Authentication实例并写入SecurityContext中,因此我们只需将SecurityContext写入共享Session即可。在需要使用用户权限的地方(如访问特定权限的url或方法的验证阶段)只需要取出Session中的SecurityContext

5.2 实现
(1) 自定义AuthenticationSuccessHandler实现类SessionAuthenticationSuccessHandler,重写onAuthenticationSuccess()方法,将SecurityContext保存到session中 


(2) 在spring-security.xml中为登录验证授权过滤器authenticationFilter配置授权成功后的处理Handler为SessionAuthenticationSuccessHandler 

(3) 自定义过滤器ValidationFilter,在doFilter()方法中实现取出session中的SecurityContext保存到SecurityContextHolder中 


(4) 在spring-security.xml为默认FilterChian添加ValidationFilter,位于FilterSecurityInterceptor (位置为FILTER_SECURITY_INTERCEPTOR)前面,这样就可以实现在权限验证之前先经过ValidationFilter将session中的SecurityContext保存到SecurityContextHolder中 

此处使用了before关键字定义了validationFilter的插入位置
--------------------- 
 

每天都在分享文章,也每天都有人想要我出来给大家分享下怎么去学习Java。大家都知道,我们是学Java全栈的,大家就肯定以为我有全套的Java系统教程。没错,我是有Java全套系统教程,进扣裙【47】974【9726】所示,今天小编就免费送!~

 

后记:对于大部分转行的人来说,找机会把自己的基础知识补齐,边工作边补基础知识,真心很重要。“我们相信人人都可以成为一个程序员,现在开始,找个师兄,带你入门,学习的路上不再迷茫。这里是ja+va修真院,初学者转行到互联网行业的聚集地。"

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值