【问题标题】:Apache Shiro: How to enforce password change?Apache Shiro:如何强制更改密码?
【发布时间】:2014-08-06 06:51:15
【问题描述】:

我正在运行一个基于 Java EE 7(JSF、JPA)和 CDI 的应用程序,使用 Shiro 进行身份验证和授权。

我有要求,用户必须在一定时间后更改密码(可由应用程序的管理员自定义,即 30 天)。在我们的用户表中,我们存储了上次设置密码时的信息,因此可以在登录时计算是否需要这样做。

计划是重新显示登录页面并表示不同的表单(更改密码而不是登录)。到目前为止,一切都很好。然而: 如何强制更改密码而不让用户导航到其他页面?

有推荐的(甚至是内置的)解决方案吗?

我的想法是实现一个过滤器,检查会话范围的登录对象是否需要重置 PW。 希望这就像创建一个新过滤器一样简单,在那里注入登录名并检查标志的状态 - 只要标志为真/他不更新他的密码,就将用户重定向到登录页面。

(我们已经有一个自定义的 cdi 感知 EnvironmentLoaderListener 来支持我们的 JPA 领域。)

新过滤器会在最后一行后面吗?

[urls]
/javax.faces.resource/** = anon
/layout.xhtml = anon
/css/** = anon
/login.xhtml = user
/logout.xhtml = logout
/** = user

所以我们有:

/** = user,pwresetfilter

欢迎对细节以及整体解决方案提出建议。

【问题讨论】:

    标签: jsf-2.2 shiro


    【解决方案1】:

    您可以使用您的解决方案,但最好是这样:

    1. 你让你自己的领域

      MyRealm extends AuthorizingRealm {
          protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
          }
      }
      

      在 doGetAuthenticationInfo 中,您将检查凭据并在需要更改密码时抛出异常。随意扩展当前使用的领域。

    2. 在 EnvironmentLoaderListener 中注册您的领域

    3. 最后你可能需要过滤器来重定向到正确的页面,或者如果你使用 REST(比如 Jersey),你可能会有一个异常映射器来响应你的浏览器客户端

    【讨论】:

    • 因此,当抛出此异常时,您将在 bean 中保留当前密码和用户名,要求更改密码,然后同时进行登录和密码更改(先密码,然后登录)?我们已经有自定义领域,所以这不是问题。但是,您不想先用他当前的密码登录用户吗?在您的场景中,您必须对完全没有任何权限的未登录用户执行“重置密码”操作。我不认为这很安全。
    • 您将用户转发到他/她写入当前密码和新密码的页面。当然,该页面会失去安全性,但这并没有什么坏处。或者更好的解决方案,你不抛出异常,但你说这个用户只有查看密码更改页面的权限。
    【解决方案2】:

    我有一个类似的要求,即身份验证后的 OTP,我使用普通过滤器过滤掉所有请求。 在使用 bean 中创建一个属性,例如 lastPasswordChangedDate,或者可以是您喜欢的 isPasswordChangerequired。并在过滤器中进行比较。

    我的简单otpFliter代码如下,但你可以根据需要自己制作jsf等:

    /**
     * Servlet Filter implementation class OTPFilter
     */
    @WebFilter(urlPatterns = {"/*"},initParams={@WebInitParam(name="enabled",value="0")})
    public class OTPFilter implements Filter {
    
        /**
         * Default constructor. 
         */
    
        boolean enabled=true;
    
    
        public OTPFilter() {
            // TODO Auto-generated constructor stub
        }
    
        /**
         * @see Filter#destroy()
         */
        public void destroy() {
            // TODO Auto-generated method stub
        }
    
        /**
         * @see Filter#doFilter(ServletRequest, ServletResponse, FilterChain)
         */
        public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
            // TODO Auto-generated method stub
            // place your code here
    
            // pass the request along the filter chain
            //System.out.println(enabled);
                if(enabled){
                if(SecurityUtils.getSubject().getPrincipal()!=null){
                    if(request instanceof HttpServletRequest ){
                        HttpSession session = ((HttpServletRequest) request).getSession();
                        LoggedInUser user =  (LoggedInUser) session.getAttribute("userinfo");
                        String url = ((HttpServletRequest) request).getRequestURL().toString();
                        //System.out.println("url is "+ url);
    
                        if( !url.contains("public") && !user.isOTPverified()){
    
    
    
                            if(user.getOTP() == null)
                                {
                                    user.setOTP(OTPUtils.generateOTP());
                                }
                            //user.setOTPverified(true);                        
                            ((HttpServletRequest) request).getRequestDispatcher("OTP.jsp").forward(request, response);
    
                            return;
                        }
                    }
                }
    
    
                }
    
            chain.doFilter(request, response);
        }
    
        /**
         * @see Filter#init(FilterConfig)
         */
        public void init(FilterConfig fConfig) throws ServletException {
            // TODO Auto-generated method stub
            //System.out.println("fConfig.getInitParameter :" + fConfig.getInitParameter("enabled"));
             enabled = fConfig.getInitParameter("enabled").equals("1");
        }
    
    }
    

    【讨论】:

    • 你是对的,没有必要使用 Shiro 过滤器。我倾向于使用过滤器解决方案。
    猜你喜欢
    • 2013-02-21
    • 2015-10-24
    • 2015-01-05
    • 1970-01-01
    • 2018-03-09
    • 2021-12-18
    • 2023-03-29
    • 1970-01-01
    • 2017-01-11
    相关资源
    最近更新 更多