如果请求的URL受Spring Security保护(或已设置class cashadvance(orm.Model):
_name = 'ga.cashadvance'
_columns = {
'id_user': fields.many2one(
'res.users', string='User', required=True, readonly=True),
'description': fields.text('Description', required=True),
'state': fields.char('State', readonly=True, required=True),
}
def addition(self, cr, uid, ids, context=None):
for adv in self.browse(cr, uid, ids, context):
new_state = chr(int(adv.state) + 1)
adv.write({'state': new_state})
return True
),则可以检查Spring Interceptor
preHandle()
方法吗?
security="none"
我的问题是,在成功登录后,我想检查用户是否已支付服务费用。如果不是,我想重定向到付款页面。我的想法是编写自定义请求范围过滤器或拦截器,并检查用户是否已在数据库中注册付款。问题是我不想过滤非安全的URL,例如资源,登录页面,错误页面等。还应提供付款页面(有安全保障)。
也许更好的想法是编写自定义安全过滤器并向@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
if(isSecured(request) && !paymentRegistered())
response.sendRedirect("/payment")
return super.preHandle(request, response, handler);
}
private boolean isSecured(HttpServletRequest request){
//how to check if url has security=none
}
对象添加自定义标记,例如Principal
以及其他安全标记:servicePayed
,enabed
等。
答案 0 :(得分:1)
我会编写自定义AuthenticationSuccessHandler,主要基于简单的实现SimpleUrlAuthenticationSuccessHandler。
在您的实现中,您应该覆盖onAuthenticationSuccess方法,并检查是否应该将用户重定向到付款页面。
/**
* Calls the parent class {@code handle()} method to forward or redirect to the target
* URL, and then calls {@code clearAuthenticationAttributes()} to remove any leftover
* session data.
*/
public void onAuthenticationSuccess(HttpServletRequest request,
HttpServletResponse response, Authentication authentication)
throws IOException, ServletException {
if(mustCompletePayment(authentication)){
handle(request, response, authentication);
clearAuthenticationAttributes(request);
}
}
然后使用身份验证对象编写一种mustCompletePayment,您必须能够从中检查用户是否必须完成付款,或者如果您在身份验证期间已经创建了自定义UserDetailsService来检查它,只需检查该指标在您的身份验证对象
中修改强> 如果您真正想要做的是避免在未完成付款的情况下对已登记用户采取任何措施,我将与授权机构进行管理。
正如我所看到的,这里的关键是将用户尚未以可以利用它的方式支付到授权层的事实进行翻译。
您已经实施了逻辑来发现用户是否已完成付款信息,因此您可以编写自己的UserDetailsService,因此在
中UserDetails loadUserByUsername(String username)throws UsernameNotFoundException
你可以检查一下,如果用户没有完成付款,只需从UserDetails中删除任何返回的granthedAuthority,只让一个人说明用户必须完成付款,让我们说ROLE_USER_HAS_NOT_PAID。
然后,在安全性http配置中(这是xml版本但可能你使用的是java配置),请进行这样的映射:
<security:http ...>
...
<security:intercept-url pattern="/secured/payment/**" access="ROLE_USER,ROLE_USER_HAS_NOT_PAID" />
<security:intercept-url pattern="/secured/**" access="ROLE_USER_HAS_PAID" />
...
</security:http>
使用此配置,无论用户是否付费,任何用户都可以访问付款页面,而其他页面仅适用于已付款的用户。但是,请务必小心,因为一旦用户付费让每个页面都可用,您必须续订用户授予的权限。
这样,AuthenticationSuccessHandler不应评估除用户授权的权限之外的其他权限,以决定将用户重定向到何处。我已经通过基于有序地图构建AuthenticationSuccessHandler多次这样做了,我为每个需要自己的登录页面的授权机构配置了登录页面。
现在任何已记录的用户操作都被禁止,如果他已完成续付,那么在尝试访问任何其他安全资源时将引发HTTP 403。但是,您希望不想阻止用户执行任何其他操作,您希望将其重定向到付款页面。在这里,您需要一个AccessDeniedHandler,您可以在其中执行大致相同的检查:
public class CustomAuthenticationAccessDeniedHandler extends
AccessDeniedHandlerImpl implements AccessDeniedHandler {
private String errorPage = "/error/403";
private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
@Override
public void handle(HttpServletRequest arg0, HttpServletResponse arg1,
AccessDeniedException arg2) throws IOException, ServletException {
SecurityContext context = SecurityContextHolder.getContext();
if(context.getAuthentication() != null && context.getAuthentication().isAuthenticated()){
if(context.getAuthentication().getAuthorities().contains("ROLE_USER_HAS_NOT_PAID")){
this.redirectStrategy.sendRedirect(arg0, arg1, "/secured/payment/pay");
return;
}
}
this.redirectStrategy.sendRedirect(arg0, arg1, this.getErrorPage());
}
public RedirectStrategy getRedirectStrategy() {
return redirectStrategy;
}
public void setRedirectStrategy(RedirectStrategy redirectStrategy) {
this.redirectStrategy = redirectStrategy;
}
@Override
public void setErrorPage(String errorPage) {
this.errorPage = errorPage;
}
public String getErrorPage() {
return errorPage;
}
}
通过这种方式,您可以将仍必须付款的用户重定向到您的付款页面,在任何其他情况下,仍然需要付费到默认的403页
答案 1 :(得分:0)
不知道是否有办法从Spring Security获取此类信息。但也许如果你没有很多不安全的网址,你可以做这样的事情:
private boolean isSecured(HttpServletRequest request) {
String requestUri = request.getRequestURI();
return !(request.getMethod().equalsIgnoreCase("GET")
&& (requestUri.contains("error/")
|| requestUri.startsWith("resources/"))
);
}
或者将这些非安全资源移动到某个公共起始路径,并使用上面代码中描述的想法。
答案 2 :(得分:0)
也许你会找到一种方法来做到这一点,但恕我直言,你不应该,因为它可能需要潜入Spring Security内部。
如果您只想按照设计方式使用Spring Security,则可以实现自定义AccessDecisionVoter
。例如,如果只能投票支持以PAYMENT开头的一个安全属性。您将该安全属性放在spring安全配置中:
<security:intercept-url pattern="/..." access="PAYMENT,ROLE_ADMIN"/>
限制对已付款或具有ADMIN角色的用户的访问权限
要声明自定义选民,您必须替换默认的访问决策管理器。首先你声明它:
<bean id="accessDecisionManager"
class="org.springframework.security.access.vote.AffirmativeBased">
<constructor-arg>
<list>
<bean class="org.springframework.security.access.vote.AuthenticatedVoter"/>
<bean class="org.springframework.security.access.vote.RoleVoter"/>
<bean class="your.package.PaymentVoter"/>
</list>
</constructor-arg>
</bean>
然后将其插入<http>
元素:
<http access-decision-manager-ref="accessDecisionManager"/>