`
y806839048
  • 浏览: 1107398 次
  • 性别: Icon_minigender_1
  • 来自: 上海
文章分类
社区版块
存档分类
最新评论

登录不会走自定义的FormAuthenticationFilter及其onLoginSuccess原因

阅读更多

登录不会走自定义的FormAuthenticationFilter及其onLoginSuccess原因

1,在自定义的类中loginUrl不是表单的提交路劲,这个提交路劲需要authc(需要访问数据库),配置好了直接调用框架的登录方法,回调自定义的onLoginSuccess之类

2,页面提交的input  name  不是框架中的username,password同名

3,自定义的获取方法应该用request.getparameter("");不应该用getAttribute();

 

4,FormAuthenticationFilter中的loginUrl和ShiroFilterFactoryBean(loginUrl登录界面)不同,

 

5,如果自定义了登录方法,最好参照框架中的AuthenticatingFilter  

Subject e = this.getSubject(request, response);

                e.login(token);

                return this.onLoginSuccess(token, e, request, response);///2自定义中也加这个

 

如果自定义的登录url和框架中的登录方法配置的loginUrl一致优先框架,不成功才再走自定义的,成功不会走

 

 

 

直接浏览器请求提交地址才走过这个定义的登录滤器,没有配置登录提交的form路径,也就是用自定义的

 

 

1,配置提交路径

2,设置此提交路径为authc

 

反之用自定的时候,提交配置去了,提交请求anon,这时也会走自定义的登录过滤器

 

 

 

 没有配置loginout   url就是用/

各种地址不配置都有默认的,只是值不一样

 

 

 

 

 

 

 

 

 

自定义的authc:

 

<bean id="myAuthenticationFilter" class="com.common.shrio.MyAuthenticationFilter" >

    <property name="loginUrl" value="/j_acegi_security_check"/>  //表单提交的路径     0   这个loginUrl和ShiroFilterFactoryBean中的loginUrl不一样,只有需要认证才能走自动提交

    <property name="successUrl" value="/flex/rbac/getLoginIndex.action" />

    </bean>

 

 

 

 

 

 

<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">

<property name="securityManager" ref="securityManager" />

<property name="loginUrl" value="/flex/rbac/preLogin.action" /> //登录界面

<property name="successUrl" value="/flex/rbac/getLoginIndex.action" />//登录成功访问显示地址http://localhost:8080/hb_telesale/flex/rbac/getLoginIndex.action;JSESSIONID=fccfab08-0342-4415-988b-2af9e13352e7

<property name="unauthorizedUrl" value="/flex/rbac/preLogin.action" />//认证失败

<property name="filterChainDefinitionMap" ref="chainDefinitionSectionMetaSource" />

<property name="filters">

<map>

<entry key="authc" value-ref="myAuthenticationFilter" />

<entry key="role" value-ref="roleAuthorizationFilter" /> 

</map>

</property>

</bean>

 

<!--/flex/rbac/preLogin.action=anon  -->

<bean id="chainDefinitionSectionMetaSource" class="com.common.shrio.ChainDefinitionSectionMetaSource">  

  

    <property name="filterChainDefinitions">

<value>

/flex/rbac/preLogin.action**=authc

/j_acegi_security_check=authc   //0

/flex/uifrm/index.jsp**=authc

/flex/rbac/getLoginIndex.action**=authc

/logout = logout

/user/logout.action = logout

<!--/** = authc-->

        </value>  

    </property>  

   </bean> 

 

 /j_acegi_security_check=anon需要认证的话就是被shiro拦住,此时用自定义的拦截器也走不到那个拦截器,被shiro拦截需要登录

 

MyAuthenticationFilter

1由于开始的时候传入的名字不对所以获取不到进入onLoginSuccess ,j_password

 

获取的时候也不对

@Override

protected String getPassword(ServletRequest servletRequest) {

//String password = (String)((HttpServletRequest) servletRequest).getAttribute("password");

//return password;

//用这种

return WebUtils.getCleanParam(servletRequest, this.getPasswordParam());

}

 

 

0处配置了点击登录的时候就自动用框架内部的登录executeLogin,无需自己写:

 

 

AuthenticatingFilter:

 

  protected boolean executeLogin(ServletRequest request, ServletResponse response) throws Exception {

        AuthenticationToken token = this.createToken(request, response);

        if(token == null) {

            String e1 = "createToken method implementation returned null. A valid non-null AuthenticationToken must be created in order to execute a login attempt.";

            throw new IllegalStateException(e1);

        } else {

            try {

                Subject e = this.getSubject(request, response);

                e.login(token);

                return this.onLoginSuccess(token, e, request, response);///2自定义中也加这个

            } catch (AuthenticationException var5) {

                return this.onLoginFailure(token, var5, request, response);

            }

        }

    }

 

 

 

MyAuthenticationFilter:

 

    @Override

protected org.apache.shiro.authc.AuthenticationToken createToken(ServletRequest servletRequest, ServletResponse servletResponse) {

String username = getUsername(servletRequest);

String password = getPassword(servletRequest);

String captchaId = getCaptchaId(servletRequest);

String captcha = getCaptcha(servletRequest);

boolean rememberMe = isRememberMe(servletRequest);

String host = getHost(servletRequest);

String validateCode = (String)((HttpServletRequest) servletRequest).getSession().getAttribute("validateCode");;

return new AuthenticationToken( username,  password,

captchaId,  captcha,  validateCode,

rememberMe,  host) ;

}

 

 

 

 

 

 

 

0处配置了点击登录的时候就自动用框架内部的登录(0处配置的是表单数据提交路劲)

 

executeLogin

无需自己写一个LoginFilter去自己登录,相当于框架已经写好了登录方法,你自己配置一个登录路劲即可  0,提交表单就是提交这个路径,自动到框架的登录方法中

 

如果自动以方法和这个框架的方法用的登录表单提交路径一样优先框架,框架正常,框架登录成功就不会在走同地址的自定义的方法,

 

 

否则再走一次自定义的方法,

 (这个地址是收集提交的参数进入框架认证提交的时机地址(表单提交地址),不是登录页面的跳转地址,如果配置成跳转登录页面的

地址,由于只是跳转登录页面,没有对应字段名的参数传递,即使自动进入框架的认证也不会成功,仍然在登录页面(你自己定义登录验证的过程

去认证,这里只做一个跳转页面是可行的)

 

自定义的方法写的时候参照这个框架方法即可  this.onLoginSuccess(token, e, request, response);///2自定义中也加这个

 

表单中的字段名称和框架中的request.getParameter("username");名称一致框架才能拿到,不能getAttribute("")

 

有这两点才会走自定义  MyAuthenticationFilter  extends  FormAuthenticationFilter    onLoginSuccess();方法  否则一直是onLoginFailure();

 

 

 

 

自定义方法:

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)

throws IOException, ServletException {

 

Subject currentUser = SecurityUtils.getSubject(); // 获取当前的Subject

// 验证是否登录成功

String resultPageURL = "/flex/rbac/preLogin.action";// InternalResourceViewResolver.FORWARD_URL_PREFIX

// + "/";

 

String username = request.getParameter("username");

String password = request.getParameter("password");

RequestDispatcher rd = null;

 

HttpServletRequest request1 =(HttpServletRequest) ((WebSubject)SecurityUtils.getSubject()).getServletRequest();  //ServletActionContext.getRequest();

Cookie[] cookies = request1.getCookies();

String username1=getCookieValue(cookies, "username");

if(username!=null&&((username1==null||username1=="")||!username.equals(username1))){

username1=username;

}

WebSession webSession= WebSessionManager.getInstance().getSession(username1);

if(webSession==null){

 

webSession=WebSessionManager.getInstance().createSession(username1);

}

String uk="Subject"+username1;

Subject currentUserrds=(Subject)webSession.getAttribute(uk);

if(currentUserrds!=null&&currentUserrds.getSession()!=null){

currentUser=currentUserrds;

}

 

// 验证是否登录成功

if (currentUser.isAuthenticated()) {

System.out.println("用户[" + currentUser.getSession().getAttribute("j_username") + "]登录认证通过");

authenticationFilter.setLoginSession(request, response);

rd = request.getRequestDispatcher("/flex/rbac/getLoginIndex.action");

// response.setBufferSize(1024000000);

rd.forward(request, response);

return;

// chain.doFilter(request, response);

} else {

if (StringUtils.isEmpty(username) || StringUtils.isEmpty(password)) {

HttpServletResponse res = (HttpServletResponse)response;

      request.setAttribute("msg", "您的账号存在信息不全的问题,请联系管理员完善信息!");

      System.out.println("登录过滤器@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");

rd = request.getRequestDispatcher("/flex/rbac/preLogin.action");

rd.forward(request, response);

return;

}

// password = MD5.encryptMD5(Base64.encode(password));

/* password = MD5.encryptMD5(Base64.encode("111111")); */

UsernamePasswordToken token = new UsernamePasswordToken(username, password); // 为了验证登录用户而封装的token

token.setRememberMe(true);// 设计记住用户

 

try {

// 在调用了login方法后,SecurityManager会收到AuthenticationToken,并将其发送给已配置的Realm执行必须的认证检查

// 每个Realm都能在必要时对提交的AuthenticationTokens作出反应

// 所以这一步在调用login(token)方法时,它会走到AuthenticationRealm.doGetAuthenticationInfo()方法中,具体验证方式详见此方法

currentUser.login(token);

                this.onLoginSuccess(token, e, request, response)//自定义的也需参考这个

resultPageURL = "/flex/rbac/preLogin.action";

} catch (UnknownAccountException uae) {

System.out.println("对用户[" + username + "]进行登录验证..验证未通过,未知账户");

request.setAttribute("msg", "未知账户");//message_login

} catch (IncorrectCredentialsException ice) {

System.out.println("对用户[" + username + "]进行登录验证..验证未通过,错误的凭证");

request.setAttribute("msg", "密码不正确");

} catch (LockedAccountException lae) {

System.out.println("对用户[" + username + "]进行登录验证..验证未通过,账户已锁定");

request.setAttribute("msg", "账户已锁定");

} catch (ExcessiveAttemptsException eae) {

System.out.println("对用户[" + username + "]进行登录验证..验证未通过,错误次数过多");

request.setAttribute("msg", "用户名或密码错误次数过多");

} catch (AuthenticationException ae) {

// 通过处理Shiro的运行时AuthenticationException就可以控制用户登录失败或密码错误时的情景

System.out.println("对用户[" + username + "]进行登录验证..验证未通过,堆栈轨迹如下");

ae.printStackTrace();

request.setAttribute("msg", "用户名或密码不正确");

}

if (currentUser.isAuthenticated()) {

System.out.println("用户[" + username + "]登录认证通过");

authenticationFilter.setLoginSession(request, response);

rd = request.getRequestDispatcher("/flex/rbac/getLoginIndex.action");

rd.forward(request, response);

return;

// chain.doFilter(request, response);

} else {

token.clear();

}

 

}

// chain.doFilter(request, response);

// HttpServletResponse res = (HttpServletResponse)response;

//      request.setAttribute("msg", "您的账号存在信息不全的问题,请联系管理员完善信息!");

//      System.out.println("登录过滤器@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");

rd = request.getRequestDispatcher(resultPageURL);

rd.forward(request, response);

return;

 

}

 

 

 

 

 

页面:

 

名字和框架AuthenticatingFilter中的获取字段一致

 

 

<form name="fm"  action="<c:url value='/j_acegi_security_check'/>" method="post" >

 

   <div class="load_bj load_h">

      <div class="load_contain">

         <div class="load_banner"><img src="${ctx}/images/main/login_001.png" width="342" height="175" /></div>

         <div class="load_tx">厚本金融电销系统</div>

        <div class="user_load">

             <p class="username"><img src="${ctx}/images/main/login_004.png" width="19" height="18" />

             <input name="username" type="text" value="" /></p>

             <p class="username pass"><img src="${ctx}/images/main/login_005.png" width="14" height="17" />

             <input name="password" type="password" value=""/></p>

             

          <p class="load_button">

          <td>

          <!-- <input type="image" name="username" src="${ctx}/images/main/button_login.jpg" /></td>

-->

          <input type="submit" value="登录" name="username"/></td>

          </p>

        </div>

      </div>

   </div>

   </form>

 

 

 

 

 注意

MyAuthenticationFilter中onLoginSuccess中的session.stop();需要注掉,否则用框架的登陆走了onLoginSuccess然后又清了session会报错

 

 

//增加登陆成功放入session

@Override

protected boolean onLoginSuccess(org.apache.shiro.authc.AuthenticationToken token, Subject subject, ServletRequest servletRequest, ServletResponse servletResponse) throws Exception {

Session session = subject.getSession();

Map<Object, Object> attributes = new HashMap<Object, Object>();

Collection<Object> keys = session.getAttributeKeys();

for (Object key : keys) {

attributes.put(key, session.getAttribute(key));

}

//session.stop();

session = subject.getSession();

for (Entry<Object, Object> entry : attributes.entrySet()) {

session.setAttribute(entry.getKey(), entry.getValue());

}

//setLoginSession(servletRequest, servletResponse);

WebUtils.getAndClearSavedRequest(servletRequest);

return super.onLoginSuccess(token, subject, servletRequest, servletResponse);

}

 

 

 

 

 

 

 

 

参考:

 

http://blog.csdn.net/u010837612/article/details/50945161

 

https://www.cnblogs.com/yoohot/p/6085830.html

  

 

 

 

 

分享到:
评论

相关推荐

    C#自定义控件库

    "C#自定义控件库"是指使用C#语言编写的、由开发者自定义的控件集合,这些控件可以扩展.NET Framework的标准控件集,为用户提供更丰富的界面元素和功能。自定义控件是软件开发中的一个重要环节,特别是在UI设计和用户...

    ASPNet中自定义Http处理及其应用

    ASPNet中自定义Http处理及其应用

    Android自定义日期选择器源码

    因此,开发者经常需要自定义日期选择器来提供更符合应用风格或特定功能的交互体验。这篇内容将深入探讨如何在Android中创建一个自定义日期选择器,并通过源码分析来增强我们的理解。 首先,我们要明白自定义日期...

    C#自定义控件之-自定义MessageBox

    在开发这些应用程序时,有时我们需要根据项目需求创建特定的用户界面元素,这正是自定义控件的作用所在。本主题将深入探讨如何在C#中自定义一个类似于系统默认`MessageBox`的控件。 `MessageBox`是.NET Framework...

    vb.net 自定义控件(含自定义对话框设置属性) 实例

    vb.net 自定义控件 自定义属性 UITypeEditor UI 类型编辑器 实例 提供一个示例 UITypeEditor,它使用 IWindowsFormsEditorService 显示用于用户输入的 Form。 IWindowsFormsEditorService 只能通过 PropertyGrid ...

    自定义QTreeView(详解)

    **自定义QTreeView详解** QTreeView是Qt库中的一个关键组件,用于展示树形数据结构。在本篇文章中,我们将深入探讨如何利用QTreeView来构建高效且可定制化的用户界面,特别是关注模型/视图架构、自定义委托、自定义...

    奥维地图-自定义地图_5.25更新.zip

    奥维地图是一款功能强大的地图应用,它允许用户进行自定义地图图源,以满足个性化的需求。自定义地图图源是奥维地图的一项重要特性,它让用户可以导入自己的地图数据,或者使用第三方提供的地图数据,从而在奥维地图...

    Winform MessageBox 自定义设计样式

    而`Show`则不会阻塞,允许用户同时操作其他窗口。 5. **图标设置**:`MessageBox`通常会显示不同类型的图标,如警告、错误、询问等。自定义`MessageBox`同样可以做到这一点,通过设置`PictureBox`控件的`Image`属性...

    Android高手进阶之自定义View,自定义属性(带进度的圆形进度条)源码

    在Android开发中,自定义View是一项重要的技能,它允许开发者根据特定需求创建独特且功能丰富的UI组件。本篇文章将深入探讨如何实现一个自定义的、带有进度指示的圆形进度条,以此来提升用户界面的交互体验。我们...

    Winform自定义MessageBox

    本文将深入探讨如何实现一个自定义的MessageBox,即"Winform自定义MessageBox"。 首先,创建一个新的Windows Form控件作为自定义消息框的基础。这个控件可以包含一个文本框来显示消息,一个定时器来实现倒计时功能...

    Apereo CAS5.2.3 自定义登录页,验证码,扩展开发,注册功能

    完整项目在https://download.csdn.net/download/u010588262/10327539 这个资源是新增功能之后的main文件夹 对应博客系列:https://blog.csdn.net/u010588262/article/category/7548325 对应博客这篇:...

    自定义DatePickerDialog的实现

    然而,有时候系统默认的样式可能无法满足我们的设计需求,这时候就需要我们自定义`DatePickerDialog`来达到预期的效果。本教程将详细讲解如何在Android中实现自定义的`DatePickerDialog`。 首先,我们需要了解`...

    C#自定义进度条大全

    在C#编程中,自定义进度条是一种常见且实用的需求,它可以为用户提供视觉反馈,显示应用程序执行任务的进度。本文将深入探讨如何在C#中实现各种自定义进度条,包括圆滑的、多边形的等不同设计样式,并提供相关的控件...

    几何画板自定义工具包-800多个小工具

    这款“几何画板自定义工具包”包含800多个精心设计的小工具,极大地扩展了软件的功能,使得用户在操作几何画板时能够更加便捷和高效。 1. **自定义工具的概念** 在几何画板中,自定义工具是用户或开发者根据需求...

    C#自定义按钮、自定义WinForm无边框窗体、自定义MessageBox窗体

    本例子包含C#自定义按钮、自定义WinForm无边框窗体、自定义MessageBox窗体 三个小例子,具体展现效果可以到:http://www.cnblogs.com/JiYF/p/8686463.html查看

    通达信自定义数据采集调用指标2.0.zip

    “SIGNALS_USER(1,0)”,里面是“1”就是自定义数据管理器里面的编号,就是通过这个函数来链接外部自定义数据的,需要用到哪些数据,我们就更改相应的数据编号就行,STICKLINE和DRAWTEXT函数一个是显示指标上显示...

    练习自定义控件代码

    在.NET框架中,C#语言提供了丰富的控件库,但有时候我们需要根据项目需求创建具有特殊功能或特定外观的自定义控件。本实践教程将深入探讨如何在C#中实现自定义控件的开发。 首先,`Form1.Designer.cs`和`Form1.cs`...

Global site tag (gtag.js) - Google Analytics