出处: https://www.cnblogs.com/lyxy/p/6694387.html
项目中需要所有首次登录的用户必须修改密码才可使用系统,项目采用的是Shiro框架。
突然想到了配置文件org.apache.shiro.spring.web.ShiroFilterFactoryBean中的loginUrl,校验未登录则跳转到登录地址。索性研究了它的源码后可以继承AccessControlFilter自定义自己的过滤器。
自定义Shiro过滤器:
package com.lwj.modules.filter;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.StringUtils;
import org.apache.shiro.web.filter.AccessControlFilter;
import org.apache.shiro.web.util.WebUtils;
import com.lwj.modules.shiro.realm.Principal;
/**
* 首次登陆必须修改密码
*
* @ClassName: ChangePasswordFilter
* @author lwj
* @version 1.0.0
*/
public class ChangePasswordFilter extends AccessControlFilter {
/**
* 登录地址
*/
static final String LOGIN_URL = "/login.html";
/**
* 修改密码地址
*/
static final String NEW_PASSWORD_URL = "/login/new_password.html";
@Override
protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue)
throws Exception {
// TODO Auto-generated method stub
return false;
}
@Override
protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
Subject subject = getSubject(request, response);
if (subject.getPrincipal() == null) {// 表示没有登录,重定向到登录页面
saveRequest(request);
WebUtils.issueRedirect(request, response, LOGIN_URL);
} else {
Principal principal = (com.lwj.modules.shiro.realm.Principal) subject.getPrincipal();
if (principal.getChangedPassword() == null || !principal.getChangedPassword()) {
if (StringUtils.hasText(NEW_PASSWORD_URL)) {// 如果首次登录未修改密码,则跳转到修改密码页面
WebUtils.issueRedirect(request, response, NEW_PASSWORD_URL);
} else {
WebUtils.toHttp(response).sendError(HttpServletResponse.SC_UNAUTHORIZED);
}
}
}
return true;
}
}
补充Principal类,这个类在登录的时候用于用户的认证,相当于保存当前登录用户的基本信息。
package com.lwj.modules.shiro.realm;
import java.io.Serializable;
/**
*
* @Description :身份信息
* @author : lwj
* @version : 1.0.0
* @Date :2016-11-13 11:21:56
*/
public class Principal implements Serializable {
/** 用户Cookie名称 */
public static final String USER_COOKIE_NAME = "u_c_n";
/** "身份信息"参数名称 */
public static final String PRINCIPAL_ATTRIBUTE_NAME = Principal.class.getName() + ".PRINCIPAL";
/**
*
*/
private static final long serialVersionUID = 1L;
/** ID */
private Integer id;
/** 用户名 */
private String username;/**
* 角色ID
*/
private Integer roleId;
/**
* 登录IP
*/
private String ip;/**
* 第一次登陆是否修改密码(平台)
*/
private Boolean changedPassword;
/**
* @param id
* ID
* @param username
* 用户名
*/
public Principal(Integer id, String username,Boolean changedPassword, Integer roleId, String ip) {
this.id = id;
this.username = username;
this.changedPassword = changedPassword;
this.roleId = roleId;
this.ip = ip;
}
/**
* 获取ID
*
* @return ID
*/
public Integer getId() {
return id;
}
/**
* 设置ID
*
* @param id
* ID
*/
public void setId(Integer id) {
this.id = id;
}
/**
* 获取用户名
*
* @return 用户名
*/
public String getUsername() {
return username;
}
/**
* 设置用户名
*
* @param username
* 用户名
*/
public void setUsername(String username) {
this.username = username;
}
public Integer getRoleId() {
return roleId;
}
public void setRoleId(Integer roleId) {
this.roleId = roleId;
}
public String getIp() {
return ip;
}
public void setIp(String ip) {
this.ip = ip;
}
public Boolean getChangedPassword() {
return changedPassword;
}
public void setChangedPassword(Boolean changedPassword) {
this.changedPassword = changedPassword;
}
}
配置shiro.xml
<!-- 自定义shiro的filter -->
<bean id="changedPassword" class="com.lwj.modules.filter.ChangePasswordFilter" />
<!-- shiroFilter -->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<!-- Shiro的核心安全接口,这个属性是必须的 -->
<property name="securityManager" ref="securityManager" />
<!-- 要求登录时的链接 -->
<property name="loginUrl" value="/login.html" />
<!-- 登录成功后要跳转的链接 -->
<property name="successUrl" value="/" />
<!-- 用户访问未对其授权的资源时,所显示的链接 -->
<property name="unauthorizedUrl" value="/common/unauthorized.html" />
<property name="filterChainDefinitions">
<value><!-- 用户首次登录必须修改密码 -->
/index/* = changedPassword
/navigation/* = authc,changedPassword
/** = authc
</value>
</property>
<property name="filters">
<map>
<entry key="changedPassword" value-ref="changedPassword" />
</map>
</property>
</bean>