/static/** = anon /error/** = anon /images/kaptcha.do* = anon /login = authc /login* = authc /smart/** = authc /customLogin = authcstom /customLogin* = authcstom /custom/** = authcstom /** = role[*]
2.两个realm
public class CustomRealm extends AuthorizingRealm { protected AccountService accountService; /** * 认证回调函数,登录时调用. */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) throws AuthenticationException { CaptchaUsernamePasswordToken token = (CaptchaUsernamePasswordToken) authcToken; doCaptchaValidate(token); User user = accountService.findUserByLoginName(token.getUsername()); if (user != null) { //2.判断是否有区,去掉该区的市、省编码 if(StringUtils.isNotBlank(user.getRegion())){ String[] resions = user.getRegion().split(","); Set resionsSet = new HashSet(); CollectionUtils.addAll(resionsSet, resions); resionsSet.remove(""); if(StringUtils.isNotBlank(user.getCity())){ String[] _citys = user.getCity().split(","); Set _citysSet = new HashSet(); CollectionUtils.addAll(_citysSet, _citys); _citysSet.remove(""); //循环遍历区 去掉多余市编码 for (String resion : resionsSet) { String _resion = resion.substring(0,resion.length()-2)+"00"; _citysSet.remove(_resion); } //重新保存 user.setCity(StringUtils.join(_citysSet.toArray(),",")); } user.setRegion(StringUtils.join(resionsSet.toArray(),",")); } //处理省多余的逗号 if(StringUtils.isNotBlank(user.getProvince())){ String[] provinces = user.getProvince().split(","); Set provinceSet = new HashSet(); CollectionUtils.addAll(provinceSet,provinces); provinceSet.remove(""); user.setProvince(StringUtils.join(provinceSet.toArray(),",")); } Session session = SecurityUtils.getSubject().getSession(); session.setAttribute("userInfo", user); byte[] salt = Encodes.decodeHex(user.getSalt()); return new SimpleAuthenticationInfo(new ShiroUser(user.getId(),user.getLoginName(), user.getName()), user.getPassword(),ByteSource.Util.bytes(salt), getName()); }else{ throw new UnknownAccountException(); } } /** * 验证码校验 * * @param token */ protected void doCaptchaValidate(CaptchaUsernamePasswordToken token) { String captcha = (String) SecurityUtils .getSubject() .getSession() .getAttribute(com.google.code.kaptcha.Constants.KAPTCHA_SESSION_KEY); if (captcha != null && !captcha.equalsIgnoreCase(token.getCaptcha())) { throw new IncorrectCaptchaException("验证码错误"); } } /** * 授权查询回调函数, 进行鉴权但缓存中无用户的授权信息时调用. */ @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { ShiroUser shiroUser = (ShiroUser) principals.getPrimaryPrincipal(); SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); // 基于Permission的权限信息 List pls = accountService.findUserPermission(shiroUser.id); for (Permission p : pls) { info.addStringPermission(p.getPerm()); } // 基于Role的权限信息 List rls = accountService.getRoleByUserId(shiroUser.id); for(Role r : rls){ info.addRole(r.getName()); } return info; } /** * 设定Password校验的Hash算法与迭代次数. */ @PostConstruct public void initCredentialsMatcher() { HashedCredentialsMatcher matcher = new HashedCredentialsMatcher( AccountService.HASH_ALGORITHM); matcher.setHashIterations(AccountService.HASH_INTERATIONS); setCredentialsMatcher(matcher); } @Autowired public void setAccountService(AccountService accountService) { this.accountService = accountService; } /** * 自定义Authentication对象,使得Subject除了携带用户的登录名外还可以携带更多信息. */ public static class ShiroUser implements Serializable { private static final long serialVersionUID = -1373760761780840081L; public Long id; public String loginName; public String name; public ShiroUser(Long id, String loginName, String name) { this.id = id; this.loginName = loginName; this.name = name; } public String getName() { return name; } public String getLoginName() { return loginName; } /** * 本函数输出将作为默认的输出. */ @Override public String toString() { return loginName; } /** * 重载hashCode,只计算loginName; */ @Override public int hashCode() { return Objects.hashCode(loginName); } /** * 重载equals,只计算loginName; */ @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; ShiroUser other = (ShiroUser) obj; if (loginName == null) { if (other.loginName != null) return false; } else if (!loginName.equals(other.loginName)) return false; return true; } } }
empty
public class CustomFormAuthenticationFilter extends FormAuthenticationFilter { // 日志组件 private Logger LOG = LoggerFactory.getLogger(CustomFormAuthenticationFilter.class); public static final String DEFAULT_CAPTCHA_PARAM = "captcha"; private String captchaParam = DEFAULT_CAPTCHA_PARAM; public static final String LOGIN_TYPE = LoginType.CUSTOM.toString(); private int maxSessions = 1; private boolean errorIfMaximumExceeded = false; private static final OnceLoginSessionMgr onceLoginSessionMgr = OnceLoginSessionMgr.getInstance(); /** * fix relogin * 拒绝二次登录或. */ protected boolean onLoginSuccess(AuthenticationToken token, Subject subject, ServletRequest request, ServletResponse response) throws Exception { if(errorIfMaximumExceeded) { return rejectSecondLogin(token, subject, request, response); } else { return invalidBeforeLogin(token, subject, request, response); } } /** * fix relogin * 拒绝二次登录. */ private boolean rejectSecondLogin(AuthenticationToken token, Subject subject, ServletRequest request,ServletResponse response) throws Exception { String username = getUsername(request); if (onceLoginSessionMgr.getShiroSubject(username) != null) { /*SecurityUtils.getSubject().logout(); throw new ReLoginException("账号已经登录,请勿重复登录");*/ } onceLoginSessionMgr.addShiroSubject(username, SecurityUtils.getSubject()); SecurityUtils.getSubject().getSession().setAttribute("username", username); return super.onLoginSuccess(token, subject, request, response); } /** * fix relogin * 注销上次登录, 让上次登录失效. * * 注: 这里登出不能使用 Subject 的 logout, 将会导致异常. * 需使用 session 的 stop 方法来登出. * @author well */ private boolean invalidBeforeLogin(AuthenticationToken token, Subject subject, ServletRequest request, ServletResponse response) throws Exception { String username = getUsername(request); Subject existSubject = onceLoginSessionMgr.getShiroSubject(username); if (existSubject != null) { /*onceLoginSessionMgr.removeShiroSubject(username); existSubject.getSession().removeAttribute("username"); existSubject.logout(); // fix: Tomcat7 Null Point Exception. logout use session stop existSubject.getSession().stop();*/ } SecurityUtils.getSubject().getSession().setAttribute("username", username); onceLoginSessionMgr.addShiroSubject(username, SecurityUtils.getSubject()); return super.onLoginSuccess(token, subject, request, response); } /** * 重写父类方法,主要是为了写登录失败日志,这里是密码失败日志 * * @author zhaobing */ @Override protected boolean onLoginFailure(AuthenticationToken token, AuthenticationException e, ServletRequest request, ServletResponse response) { String username = getUsername(request); SecurityUtils.getSubject().getSession().setAttribute("username", username); onceLoginSessionMgr.addShiroSubject(username, SecurityUtils.getSubject()); return super.onLoginFailure(token,e,request,response); } @Override protected CaptchaUsernamePasswordToken createToken(ServletRequest request, ServletResponse response) { String username = getUsername(request); String password = getPassword(request); String captcha = getCaptcha(request); boolean rememberMe = isRememberMe(request); String host = getHost(request); return new CaptchaUsernamePasswordToken(username, password.toCharArray(), rememberMe, host, captcha,LOGIN_TYPE); } public String getCaptchaParam() { return captchaParam; } public void setCaptchaParam(String captchaParam) { this.captchaParam = captchaParam; } protected String getCaptcha(ServletRequest request) { return WebUtils.getCleanParam(request, getCaptchaParam()); } public int getMaxSessions() { return maxSessions; } public void setMaxSessions(int maxSessions) { this.maxSessions = maxSessions; } public boolean isErrorIfMaximumExceeded() { return errorIfMaximumExceeded; } public void setErrorIfMaximumExceeded(boolean errorIfMaximumExceeded) { this.errorIfMaximumExceeded = errorIfMaximumExceeded; } /** * 获取当前网络ip * @param req * @return */ private String getIpAddr(ServletRequest req){ HttpServletRequest request = (HttpServletRequest)req; String ipAddress = request.getHeader("x-forwarded-for"); if(ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) { ipAddress = request.getHeader("Proxy-Client-IP"); } if(ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) { ipAddress = request.getHeader("WL-Proxy-Client-IP"); } if(ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) { ipAddress = request.getRemoteAddr(); if(ipAddress.equals("127.0.0.1") || ipAddress.equals("0:0:0:0:0:0:0:1")){ //根据网卡取本机配置的IP InetAddress inet=null; try { inet = InetAddress.getLocalHost(); } catch (UnknownHostException e) { e.printStackTrace(); } ipAddress= inet.getHostAddress(); } } //对于通过多个代理的情况,第一个IP为客户端真实IP,多个IP按照','分割 if(ipAddress!=null && ipAddress.length()>15){ //"***.***.***.***".length() = 15 if(ipAddress.indexOf(",")>0){ ipAddress = ipAddress.substring(0,ipAddress.indexOf(",")); } } return ipAddress; } }
public class CaptchaFormAuthenticationFilter extends FormAuthenticationFilter { // 日志组件 private Logger LOG = LoggerFactory.getLogger(CaptchaFormAuthenticationFilter.class); public static final String DEFAULT_CAPTCHA_PARAM = "captcha"; private String captchaParam = DEFAULT_CAPTCHA_PARAM; public static final String LOGIN_TYPE = LoginType.SMART.toString(); private int maxSessions = 1; private boolean errorIfMaximumExceeded = false; private static final OnceLoginSessionMgr onceLoginSessionMgr = OnceLoginSessionMgr.getInstance(); /** * fix relogin * 拒绝二次登录或. */ protected boolean onLoginSuccess(AuthenticationToken token, Subject subject, ServletRequest request, ServletResponse response) throws Exception { if(errorIfMaximumExceeded) { return rejectSecondLogin(token, subject, request, response); } else { return invalidBeforeLogin(token, subject, request, response); } } /** * fix relogin * 拒绝二次登录. */ private boolean rejectSecondLogin(AuthenticationToken token, Subject subject, ServletRequest request,ServletResponse response) throws Exception { String username = getUsername(request); if (onceLoginSessionMgr.getShiroSubject(username) != null) { /*SecurityUtils.getSubject().logout(); throw new ReLoginException("账号已经登录,请勿重复登录");*/ } onceLoginSessionMgr.addShiroSubject(username, SecurityUtils.getSubject()); SecurityUtils.getSubject().getSession().setAttribute("username", username); return super.onLoginSuccess(token, subject, request, response); } /** * fix relogin * 注销上次登录, 让上次登录失效. * * 注: 这里登出不能使用 Subject 的 logout, 将会导致异常. * 需使用 session 的 stop 方法来登出. * @author */ private boolean invalidBeforeLogin(AuthenticationToken token, Subject subject, ServletRequest request, ServletResponse response) throws Exception { String username = getUsername(request); Subject existSubject = onceLoginSessionMgr.getShiroSubject(username); if (existSubject != null) { /*onceLoginSessionMgr.removeShiroSubject(username); existSubject.getSession().removeAttribute("username"); existSubject.logout(); // fix: Tomcat7 Null Point Exception. logout use session stop existSubject.getSession().stop();*/ } SecurityUtils.getSubject().getSession().setAttribute("username", username); onceLoginSessionMgr.addShiroSubject(username, SecurityUtils.getSubject()); return super.onLoginSuccess(token, subject, request, response); } /** * 重写父类方法,主要是为了写登录失败日志,这里是密码失败日志 * * @author */ @Override protected boolean onLoginFailure(AuthenticationToken token, AuthenticationException e, ServletRequest request, ServletResponse response) { String username = getUsername(request); SecurityUtils.getSubject().getSession().setAttribute("username", username); onceLoginSessionMgr.addShiroSubject(username, SecurityUtils.getSubject()); return super.onLoginFailure(token,e,request,response); } @Override protected CaptchaUsernamePasswordToken createToken(ServletRequest request, ServletResponse response) { String username = getUsername(request); String password = getPassword(request); String captcha = getCaptcha(request); boolean rememberMe = isRememberMe(request); String host = getHost(request); return new CaptchaUsernamePasswordToken(username, password.toCharArray(), rememberMe, host, captcha,LOGIN_TYPE); } public String getCaptchaParam() { return captchaParam; } public void setCaptchaParam(String captchaParam) { this.captchaParam = captchaParam; } protected String getCaptcha(ServletRequest request) { return WebUtils.getCleanParam(request, getCaptchaParam()); } public int getMaxSessions() { return maxSessions; } public void setMaxSessions(int maxSessions) { this.maxSessions = maxSessions; } public boolean isErrorIfMaximumExceeded() { return errorIfMaximumExceeded; } public void setErrorIfMaximumExceeded(boolean errorIfMaximumExceeded) { this.errorIfMaximumExceeded = errorIfMaximumExceeded; } /** * 获取当前网络ip * @param req * @return */ private String getIpAddr(ServletRequest req){ HttpServletRequest request = (HttpServletRequest)req; String ipAddress = request.getHeader("x-forwarded-for"); if(ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) { ipAddress = request.getHeader("Proxy-Client-IP"); } if(ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) { ipAddress = request.getHeader("WL-Proxy-Client-IP"); } if(ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) { ipAddress = request.getRemoteAddr(); if(ipAddress.equals("127.0.0.1") || ipAddress.equals("0:0:0:0:0:0:0:1")){ //根据网卡取本机配置的IP InetAddress inet=null; try { inet = InetAddress.getLocalHost(); } catch (UnknownHostException e) { e.printStackTrace(); } ipAddress= inet.getHostAddress(); } } //对于通过多个代理的情况,第一个IP为客户端真实IP,多个IP按照','分割 if(ipAddress!=null && ipAddress.length()>15){ //"***.***.***.***".length() = 15 if(ipAddress.indexOf(",")>0){ ipAddress = ipAddress.substring(0,ipAddress.indexOf(",")); } } return ipAddress; } }
public enum LoginType { CUSTOM("Custom"), SMART("Smart"); private String type; private LoginType(String type) { this.type = type; } @Override public String toString() { return this.type.toString(); } }
public class UsernamePasswordToken extends UsernamePasswordToken { private static final long serialVersionUID = -4007351673293500161L; private String captcha; private String ukeyId; private String loginType; public UsernamePasswordToken(String username, char[] password, boolean rememberMe, String host, String captcha, String ukeyId,String loginType) { super(username, password, rememberMe, host); this.captcha = captcha; this.ukeyId = ukeyId; this.loginType = loginType; } public String getLoginType() { return loginType; } public void setLoginType(String loginType) { this.loginType = loginType; } public UsernamePasswordToken(String username, char[] password, boolean rememberMe, String host, String captcha,String loginType) { this(username, password, rememberMe, host, captcha, null,loginType); } public String getCaptcha() { return captcha; } public void setCaptcha(String captcha) { this.captcha = captcha; } public String getUkeyId() { return ukeyId; } public void setUkeyId(String ukeyId) { this.ukeyId = ukeyId; } }
public class CustomizedModularRealmAuthenticator extends ModularRealmAuthenticator{ @Override protected AuthenticationInfo doAuthenticate(AuthenticationToken authenticationToken) throws AuthenticationException { // 判断getRealms()是否返回为空 assertRealmsConfigured(); // 强制转换回自定义的CustomizedToken CaptchaUsernamePasswordToken customizedToken = (CaptchaUsernamePasswordToken) authenticationToken; // 登录类型 String loginType = customizedToken.getLoginType(); // 所有Realm Collection realms = getRealms(); // 登录类型对应的所有Realm Collection typeRealms = new ArrayList<>(); for (Realm realm : realms) { if (realm.getName().contains(loginType)) typeRealms.add(realm); } // 判断是单Realm还是多Realm if (typeRealms.size() == 1) return doSingleRealmAuthentication(typeRealms.iterator().next(), customizedToken); else return doMultiRealmAuthentication(typeRealms, customizedToken); } }
@Controller @RequestMapping(value = "/customLogin") public class CustomLoginController { @RequestMapping(method = RequestMethod.GET) public String customLogin() { // 如果已登录,直接跳转至主页 ShiroUser user = (ShiroUser) SecurityUtils.getSubject().getPrincipal(); if (user != null) { return "redirect:custom/main/index"; } return "account/customLogin"; } @RequestMapping(method = RequestMethod.POST) public String fail(@RequestParam(FormAuthenticationFilter.DEFAULT_USERNAME_PARAM) String userName, Model model) { model.addAttribute(FormAuthenticationFilter.DEFAULT_USERNAME_PARAM, userName); return "account/customLogin"; } }
@Controller @RequestMapping(value = "/smartLogin") public class SmartLoginController { @RequestMapping(method = RequestMethod.GET) public String smartLogin() { // 如果已登录,直接跳转至主页 ShiroUser user = (ShiroUser) SecurityUtils.getSubject().getPrincipal(); if (user != null) { return "redirect:smart/main/index"; } return "account/login"; } @RequestMapping(method = RequestMethod.POST) public String fail(@RequestParam(FormAuthenticationFilter.DEFAULT_USERNAME_PARAM) String userName, Model model) { model.addAttribute(FormAuthenticationFilter.DEFAULT_USERNAME_PARAM, userName); return "account/login"; } }