public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
// 必须设置 SecurityManager
shiroFilterFactoryBean.setSecurityManager(securityManager);
shiroFilterFactoryBean.setLoginUrl("/login");
shiroFilterFactoryBean.setSuccessUrl("/index");
shiroFilterFactoryBean.setUnauthorizedUrl("/403");
// private Map filters; shiro有一些默认的拦截器
// 比如auth,它就是FormAuthenticationFilter表单拦截器 <取名,拦截器地址>,可以自定义拦截器放在这
// private Map filterChainDefinitionMap; 哪些路径会被此拦截器拦截到
// 拦截器.
Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();
// 配置不会被拦截的链接 顺序判断
filterChainDefinitionMap.put("/static/**", "anon");
filterChainDefinitionMap.put("/ajaxLogin", "anon");
filterChainDefinitionMap.put("/项目的Namespace/userlogin", "anon");
filterChainDefinitionMap.put("/swagger-ui.html#", "anon");
// 过滤链定义,从上向下顺序执行,一般将 /**放在最为下边
// <!-- authc:所有url都必须认证通过才可以访问; anon:所有url都都可以匿名访问;user:remember me的可以访问-->
filterChainDefinitionMap.put("/fine", "user");
filterChainDefinitionMap.put("/项目的Namespace/**", "authc");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
System.out.println("Shiro拦截器工厂类注入成功");
return shiroFilterFactoryBean;
}
<bean id="securityManager"
class="com.key.common.plugs.security.MyDefaultWebSecurityManager">
<property name="realm" ref="shiroDbRealm" />
<property name="rememberMeManager" ref="rememberMeManager" />
</bean>
<bean id="formAuthFilter"
class="com.key.common.plugs.security.FormAuthenticationWithLockFilter">
<property name="maxLoginAttempts" value="100" />
<property name="successAdminUrl" value="/main.action?menu=3" />
<property name="successAdminRole" value="admin" />
<property name="rememberMeParam" value="rememberMe" />
</bean>
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<property name="securityManager" ref="securityManager" />
<!-- 系统登陆 -->
<property name="loginUrl" value="/login.jsp" />
<!-- 登陆成功的action -->
<property name="successUrl" value="/login/main.action" />
<!-- 登陆失败的url跳转 -->
<property name="unauthorizedUrl" value="/login.jsp?una=0" />
<property name="filters">
<util:map>
<entry key="authc" value-ref="formAuthFilter">
</entry>
</util:map>
</property>
<property name="filterChainDefinitions">
<value>
/login.jsp = authc
/ic/** = user
/项目的Namespace/** = user
/项目的Namespace/** = user
/sys/** = roles[admin]
package com.key.common.plugs.security;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import com.key.common.base.entity.User;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.ExcessiveAttemptsException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;
import org.springframework.beans.factory.annotation.Autowired;
import com.key.common.base.service.AccountManager;
public class FormAuthenticationWithLockFilter extends FormAuthenticationFilter {
Log log=LogFactory.getLog(FormAuthenticationWithLockFilter.class);
private long maxLoginAttempts = 10;
public static ConcurrentHashMap<String, AtomicLong> accountLockMap = new ConcurrentHashMap<String, AtomicLong>();
private String successAdminUrl;
private String successAdminRole;
@Autowired
protected AccountManager accountManager;
@Override
public boolean executeLogin(ServletRequest request, ServletResponse response) throws Exception {
AuthenticationToken token = createToken(request, response);
if (token == null) {
String msg = "createToken method implementation returned null. A valid non-null AuthenticationToken "
+ "must be created in order to execute a login attempt.";
throw new IllegalStateException(msg);
}
if (checkIfAccountLocked(request)) {
return onLoginFailure(token, new ExcessiveAttemptsException(), request, response);
} else {
if (!doLogin(request, response, token)) {
resetAccountLock(getUsername(request));
return false;
}
return true;
}
}
/* 检查账户锁定状态 */
public boolean checkIfAccountLocked(ServletRequest request) {
String username = getUsername(request);
if (username!=null && accountLockMap.get((String) username) != null) {
long remainLoginAttempts = accountLockMap.get((String) username).get();
if (remainLoginAttempts <= 0) {
return true;
}
}
return false;
}
private boolean doLogin(ServletRequest request, ServletResponse response, AuthenticationToken token)
throws Exception {
try {
//shrio的subject
Subject subject = getSubject(request, response);
subject.login(token);
// User user = accountManager.findUserByLoginName(getUsername(request));
User user = accountManager.findUserByLoginNameOrEmail(getUsername(request));
return onLoginSuccess(token, subject, request, response);
} catch (IncorrectCredentialsException e) {//用户名或信息错误
decreaseAccountLoginAttempts(request);//减少账户登陆尝试次数
checkIfAccountLocked(request);
return onLoginFailure(token, e, request, response);
} catch (AuthenticationException e) {//认证错误
return onLoginFailure(token, e, request, response);
}
}
/* 减少账户登陆尝试次数 */
public void decreaseAccountLoginAttempts(ServletRequest request) {
AtomicLong initValue = new AtomicLong(maxLoginAttempts);
AtomicLong remainLoginAttempts = accountLockMap.putIfAbsent(getUsername(request), new AtomicLong(maxLoginAttempts));
if (remainLoginAttempts == null) {
remainLoginAttempts = initValue;
}
remainLoginAttempts.getAndDecrement();
accountLockMap.put(getUsername(request), remainLoginAttempts);
}
public void resetAccountLock(String username) {
accountLockMap.put(username, new AtomicLong(maxLoginAttempts));
}
public void setMaxLoginAttempts(long maxLoginAttempts) {
this.maxLoginAttempts = maxLoginAttempts;
}
public void setSuccessAdminUrl(String successAdminUrl) {
this.successAdminUrl = successAdminUrl;
}
public void setSuccessAdminRole(String successAdminRole) {
this.successAdminRole = successAdminRole;
}
/* 得到某个账号还可以登录次数 */
public Long getAccountLocked(String username){
long remainLoginAttempts=0;
if (username!=null && accountLockMap.get((String) username) != null) {
remainLoginAttempts = accountLockMap.get((String) username).get();
}
return remainLoginAttempts+1;
}
/* 重写登录失败,加入了失败时还可以重试的次数信息 */
@Override
protected boolean onLoginFailure(AuthenticationToken token,
AuthenticationException e, ServletRequest request,
ServletResponse response) {
request.setAttribute("remainLoginAttempt", getAccountLocked(getUsername(request)));
return super.onLoginFailure(token, e, request, response);
}
@Override
protected String getUsername(ServletRequest request) {
// TODO Auto-generated method stub
String username = super.getUsername(request);
if(username==null){
Object temp=request.getAttribute(getUsernameParam());
username=temp!=null?temp.toString():null;
}
return username;
}
@Override
protected String getPassword(ServletRequest request) {
String password = super.getPassword(request);
if(password==null){
Object temp=request.getAttribute(getPasswordParam());
password=temp!=null?temp.toString():null;
}
return password;
}
@Override
protected boolean isRememberMe(ServletRequest request) {
// TODO Auto-generated method stub
return super.isRememberMe(request);
}
}
部分参考文章
shiro表单拦截器FormAuthenticationFilter,登录成功后如何继续访问原请求
org.apache.shiro.web.filter.authc.FormAuthenticationFilter