登录不会走自定义的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&¤tUserrds.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