比如說我想 加一個驗證碼 認(rèn)證,原來的userNamePasswordToken 就不夠用了,我需要自定義一個新的token. public class SecurityToken extends UsernamePasswordToken { /** * 驗證碼 */ private String captcha; /** * 系統(tǒng)生成的驗證碼(從session獲?。? */ private String captchaSession; /** * 構(gòu)造函數(shù) */ public SecurityToken() { super(); } /** * 構(gòu)造函數(shù) * @param username 用戶名 * @param password 用戶密碼 * @param captcha 驗證碼 */ public SecurityToken(String username, String password, String captcha) { super(username, password); this.captcha = captcha; } /** * 構(gòu)造函數(shù) * @param username 用戶名 * @param password 用戶密碼 * @param captcha 驗證碼 * @param host 主機 */ public SecurityToken(String username, String password, String captcha, String host) { super(username, password, host); this.captcha = captcha; } /** * 構(gòu)造函數(shù) * @param username 用戶名 * @param password 用戶密碼 * @param captcha 驗證碼 * @param rememberMe 記住我 */ public SecurityToken(String username, String password, String captcha, boolean rememberMe) { super(username, password, rememberMe); this.captcha = captcha; } /** * 構(gòu)造函數(shù) * @param username 用戶名 * @param password 用戶密碼 * @param captcha 驗證碼 * @param rememberMe 記住我 * @param host 主機 */ public SecurityToken(String username, String password, String captcha, boolean rememberMe, String host) { super(username, password, rememberMe, host); this.captcha = captcha; } /** * 獲得驗證碼 * @return 驗證碼 */ public String getCaptcha() { return captcha; } /** * 設(shè)置驗證碼 * @param captcha 驗證碼 */ public void setCaptcha(String captcha) { this.captcha = captcha; } /** * 獲得系統(tǒng)生成的驗證碼 * @return 系統(tǒng)生成的驗證碼 */ public String getCaptchaSession() { return captchaSession; } /** * 設(shè)置系統(tǒng)生成的驗證碼 * @param captchaSession 系統(tǒng)生成的驗證碼 */ public void setCaptchaSession(String captchaSession) { this.captchaSession = captchaSession; } } 在這基礎(chǔ)上,我想要定義認(rèn)證過濾器: public class SecurityAuthcFilter extends FormAuthenticationFilter { private static Logger logger = LoggerFactory.getLogger(SecurityAuthcFilter.class); /** * 默認(rèn)的驗證碼輸入框標(biāo)識 */ public static final String DEFAULT_CAPTCHA_PARAM = "captcha"; /** * 默認(rèn)登錄后的轉(zhuǎn)向邏輯(是否跳轉(zhuǎn)到登錄前的界面) */ public static final boolean DEFAULT_REDIRECT_TO_SAVED_REQUEST = false; /** * 默認(rèn)的編碼方式 */ public static final String DEFAULT_CHARACTER_ENCODING = "UTF-8"; /** * 驗證碼輸入框標(biāo)識 */ private String captchaParam = DEFAULT_CAPTCHA_PARAM; /** * 登錄后的轉(zhuǎn)向邏輯(是否跳轉(zhuǎn)到登錄前的界面) */ private boolean redirectToSavedRequest = DEFAULT_REDIRECT_TO_SAVED_REQUEST; /** * 編碼方式 */ private String characterEncoding = DEFAULT_CHARACTER_ENCODING; /** * 驗證碼的屬性Key(用于從session中獲取系統(tǒng)生成的驗證碼) */ public static final String CAPTCHA_SESSION = "SECURITY.LOGIN.CAPTCHA"; /** * 登錄錯誤輸入框元素名稱 */ public static final String LOGIN_FAILED_ELEMENT = "SECURITY.LOGIN.FAILED.ELEMENT"; /** * 登錄錯誤提示信息 */ public static final String LOGIN_FAILED_MESSAGE = "SECURITY.LOGIN.FAILED.MESSAGE"; /** * 根據(jù)登錄信息創(chuàng)建登錄用戶的token * @param request ServletRequest對象 * @param response ServletResponse對象 * @return 登錄用戶的token */ @Override protected AuthenticationToken createToken(ServletRequest request, ServletResponse response) { try { request.setCharacterEncoding(characterEncoding); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } String username = getUsername(request); String password = getPassword(request); String captcha = getCaptcha(request); String captchaSession = getCaptchaSession(request); boolean rememberMe = isRememberMe(request); String host = getHost(request); SecurityToken token = new SecurityToken(username, password, captcha, rememberMe, host); token.setCaptchaSession(captchaSession); return token; } /** * 獲取驗證碼輸入框標(biāo)識 * @return 驗證碼輸入框標(biāo)識 */ public String getCaptchaParam() { return captchaParam; } /** * 設(shè)置驗證碼輸入框標(biāo)識 * @param captchaParam 驗證碼輸入框標(biāo)識 */ public void setCaptchaParam(String captchaParam) { this.captchaParam = captchaParam; } /** * 獲取驗證碼輸入框標(biāo)識 * @param request ServletRequest對象 * @return 驗證碼輸入框標(biāo)識 */ protected String getCaptcha(ServletRequest request) { return WebUtils.getCleanParam(request, getCaptchaParam()); } /** * 獲取驗證碼輸入框標(biāo)識 * @param request ServletRequest對象 * @return 驗證碼輸入框標(biāo)識 */ protected String getCaptchaSession(ServletRequest request) { Subject subject = SecurityUtils.getSubject(); Session session = subject.getSession(); return (String)session.getAttribute(CAPTCHA_SESSION); } /** * 判斷是否跳轉(zhuǎn)到登錄前的界面 * @return 是否跳轉(zhuǎn)到登錄前的界面 */ public boolean isRedirectToSavedRequest() { return redirectToSavedRequest; } /** * 設(shè)置是否跳轉(zhuǎn)到登錄前的界面 * @param redirectToSavedRequest 是否跳轉(zhuǎn)到登錄前的界面 */ public void setRedirectToSavedRequest(boolean redirectToSavedRequest) { this.redirectToSavedRequest = redirectToSavedRequest; } /** * 獲取編碼方式 * @return 編碼方式 */ public String getCharacterEncoding() { return characterEncoding; } /** * 設(shè)置編碼方式 * @param characterEncoding 編碼方式 */ public void setCharacterEncoding(String characterEncoding) { this.characterEncoding = characterEncoding; } /** * 登錄失敗后的處理 * @param request ServletRequest對象 * @param ae 用戶認(rèn)證錯誤異常信息 */ @Override protected void setFailureAttribute(ServletRequest request, AuthenticationException ae) { String element = getUsernameParam(); if(ae instanceof AccountNotFoundException || ae instanceof AccountStatusException || ae instanceof AccountUnknownException) { element = getUsernameParam(); } if(ae instanceof IncorrectPasswordException) { element = getPasswordParam(); } if(ae instanceof IncorrectCaptchaException) { element = getCaptchaParam(); } if(ae instanceof InactivePasswordException) { element = getPasswordParam(); } request.setAttribute(LOGIN_FAILED_ELEMENT, element); request.setAttribute(LOGIN_FAILED_MESSAGE, ae.getMessage()); } /** * 登錄成功后的處理 * @param token 登錄用戶的token * @param subject 登錄用戶的Shiro信息 * @param request ServletRequest對象 * @param response ServletResponse對象 * @return 是否登錄成功 * @throws Exception 異常信息 */ @Override protected boolean onLoginSuccess(AuthenticationToken token, Subject subject, ServletRequest request, ServletResponse response) throws Exception { //登錄成功后,從session中去除校驗碼 Session session = subject.getSession(); session.removeAttribute(CAPTCHA_SESSION); //觸發(fā)執(zhí)行鑒權(quán)方法 SecurityManager.isSessionUserAdminRole(); if (redirectToSavedRequest) { return super.onLoginSuccess(token, subject, request, response); } else { WebUtils.issueRedirect(request, response, getSuccessUrl()); return false; } } } 配置文件配置: <bean id="securityAuthcFilter" class="com.credithc.scs.security.SecurityAuthcFilter"> <!--<property name="failureKeyAttribute" value=""/>--> </bean> <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"> <property name="securityManager" ref="securityManager"/> <property name="loginUrl" value="/doLogin"/> <property name="successUrl" value="/home"/> <property name="unauthorizedUrl" value="/login"/> <property name="filters"> <util:map> <entry key="authc" value-ref="securityAuthcFilter"/> </util:map> </property> <property name="filterChainDefinitions"> <value> /logout.do*=anon /casticketerror.do*=anon # 權(quán)限配置示例 /security/account/view.do=authc,perms[SECURITY_ACCOUNT_VIEW] /** = authc </value> </property> </bean> 這樣再訪問 /** 目錄的時候就會走到 SecurityAuthcFilter 這個類做認(rèn)證了。 因為這個類創(chuàng)建的token 是SecurityToken,默認(rèn)的realm 處理不了, 所以我們還要 定義自己的realm:
public class SecurityRealm extends AuthorizingRealm { private static Logger logger = LoggerFactory.getLogger(SecurityRealm.class); // @Autowired // private ISecurityDelegate securityDelegate; // @Autowired // private ILoginLogDelegate loginLogDelegate; @Autowired private SecurityService securityService; /** * 是否啟用驗證碼 */ private boolean isCaptchaEnable = false; /** * 登錄錯誤的異常信息:驗證碼錯誤異常 */ public static final String INCORRECT_CAPTCHA_EXCEPTION_MSG = "驗證碼錯誤!"; /** * 登錄錯誤的異常信息:密碼錯誤異常 */ public static final String INCORRECT_PASSWORD_USERNAME_EXCEPTION_MSG = "用戶名或密碼錯誤!"; /** * 登錄錯誤的異常信息:密碼過期異常 */ public static final String INACTIVE_PASSWORD_EXCEPTION_MSG = "密碼已過期,請聯(lián)系管理員!"; /** * 登錄錯誤的異常信息:未知異常 */ public static final String ACCOUNT_UNKNOWN_EXCEPTION_MSG = "未知系統(tǒng)異常!"; /** * 用戶、員工正常狀態(tài)取值 */ private static final String STATUS_NORMAL = "A"; @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { SysUserDTO sysUser = (SysUserDTO) principals.fromRealm(getName()).iterator().next(); if (sysUser == null) { logger.info("獲取鑒權(quán)信息:無法獲得登錄用戶信息"); return null; } try { logger.info("獲取鑒權(quán)信息:開始獲取登錄用戶【{}】鑒權(quán)信息", sysUser.getLoginName()); SimpleAuthorizationInfo info = securityService.doGetAuthorizationInfo(sysUser); logger.info("獲取鑒權(quán)信息:成功獲取登錄用戶【{}】鑒權(quán)信息", sysUser.getLoginName()); return info; } catch (SysException e) { e.printStackTrace(); logger.error("獲取鑒權(quán)信息:獲取登錄用戶【{}】鑒權(quán)信息時發(fā)生異常:{}", sysUser.getLoginName(), e.getErrMsg()); throw new AccountUnknownException(e.getErrMsg()); } } /** * 獲得用戶認(rèn)證信息 * * @param authenticationToken * 用戶登錄的token * @return 用戶認(rèn)證信息 * @throws AuthenticationException * 用戶認(rèn)證異常 */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { SecurityToken token = (SecurityToken) authenticationToken; Session session = SecurityUtils.getSubject().getSession(); logger.debug("獲取認(rèn)證信息:開始獲取登錄用戶【{}】認(rèn)證信息", token.getUsername()); /** * 驗證碼校驗 */ if (isCaptchaEnable) { if (!StringUtils.equalsIgnoreCase(token.getCaptcha(), token.getCaptchaSession())) { throw new IncorrectCaptchaException(INCORRECT_CAPTCHA_EXCEPTION_MSG); } logger.debug("獲取認(rèn)證信息:登錄用戶【{}】通過驗證碼校驗", token.getUsername()); } /** * 登錄帳戶信息校驗(校驗帳戶是否存在,以及校驗帳戶狀態(tài)) */ logger.debug("獲取認(rèn)證信息:開始數(shù)據(jù)庫驗證登錄用戶【{}】信息", token.getUsername()); SysUserDTO sysUser = null; try { sysUser = securityService.doGetAuthenticationInfo(token.getUsername()); } catch (Exception e) { e.printStackTrace(); logger.error("獲取認(rèn)證信息:獲取登錄用戶【{}】鑒權(quán)信息時發(fā)生異常:{}", token.getUsername(), e.getMessage()); throw new AccountUnknownException(ACCOUNT_UNKNOWN_EXCEPTION_MSG); } if (sysUser == null) { logger.debug("獲取認(rèn)證信息:登錄用戶【{}】不存在", token.getUsername()); throw new AccountNotFoundException(INCORRECT_PASSWORD_USERNAME_EXCEPTION_MSG); } if (!StringUtils.equals(STATUS_NORMAL, sysUser.getSts()) || !StringUtils.equals(STATUS_NORMAL, sysUser.getSts())) { logger.debug("獲取認(rèn)證信息:登錄用戶【{}】狀態(tài)異常", token.getUsername()); throw new AccountStatusException(INCORRECT_PASSWORD_USERNAME_EXCEPTION_MSG); } if (!StringUtils.equals(String.copyValueOf(token.getPassword()), sysUser.getPassword())) { logger.debug("獲取認(rèn)證信息:登錄用戶【{}】密碼錯誤", token.getUsername()); throw new IncorrectPasswordException(INCORRECT_PASSWORD_USERNAME_EXCEPTION_MSG); } CacheManager cacheManager = CacheManager.getInstance(); String inactiveFlag = (String) cacheManager.get(ConstantsUtils.CACHE_SYSTEM + ".table.cache.idvalue.sysconfig", "INACTIVEL_FLAG"); if (StringUtils.isNotBlank(inactiveFlag) && inactiveFlag.equals("Y")) { if (sysUser.getPwdInactiveTime() != null) { DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); try { Date startDate = df.parse(sysUser.getPwdInactiveTime()); Date endDate = df.parse(df.format(new Date())); long day = (startDate.getTime() - endDate.getTime()) / (24 * 60 * 60 * 1000); session.setAttribute("inactiveDays", day); if (df.parse(sysUser.getPwdInactiveTime()).getTime() < df.parse(df.format(new Date())).getTime()) { throw new InactivePasswordException(INACTIVE_PASSWORD_EXCEPTION_MSG); } } catch (ParseException e) { e.printStackTrace(); } } } logger.debug("獲取認(rèn)證信息:完成數(shù)據(jù)庫驗證登錄用戶【{}】信息", token.getUsername()); /* * try { LoginLog loginLog = new LoginLog(); * loginLog.setSysUserId(sysUser.getSysUserId()); * loginLog.setIpAddr(token.getHost()); loginLog.setMacAddr(null); * loginLog = loginLogService.insert(loginLog); * session.setAttribute("loginLogId", loginLog.getLoginLogId()); } catch * (SysException e) { e.printStackTrace(); } catch (AppException e) { * e.printStackTrace(); } */ logger.debug("獲取認(rèn)證信息:記錄登錄用戶【{}】日志", token.getUsername()); return new SimpleAuthenticationInfo(sysUser, sysUser.getPassword(), getName()); } /** * 設(shè)置是否啟用校驗碼 * * @param captchaEnable * 是否啟用校驗碼 */ public void setCaptchaEnable(boolean captchaEnable) { isCaptchaEnable = captchaEnable; } } 配置realm: <bean id="securityRealm" class="com.credithc.scs.security.SecurityRealm"> <property name="captchaEnable" value="true"/> <property name="cacheManager" ref="securityCacheManager"/> </bean> <!-- 創(chuàng)建Shiro的securityManager,并設(shè)置了realm和cacheManager兩個關(guān)鍵屬性 --> <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"> <property name="realm" ref="securityRealm"/> </bean> |
|