項目中需要所有首次登錄的用戶必須修改密碼才可使用系統,項目采用的是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>
