java中的接口是类吗
289
2022-11-20
springmvc集成shiro登录失败处理操作
一般的登录流程会有:用户名不存在,密码错误,验证码错误等..
在集成shiro后,应用程序的外部访问权限以及访问控制交给了shiro来管理。
shiro提供了两个主要功能:认证(Authentication)和授权(Authorization);认证的作用是证明自身可以访问,一般是用户名加密码,授权的作用是谁可以访问哪些资源,通过开发者自己的用户角色权限系统来控制。
shiro的会话管理和缓存管理不在本文范围内。
下面通过登录失败的处理流程来介绍springmvc与shiro的集成。
依赖项目
依赖名称
版本
spring
4.1.4.RELEASE
shiro
1.2.2
self4j
1.7.5
log4j
1.2.17
在web.xml里配置shiro
新建一个spring-context-shiro.xml配置shiro相关信息,使用spring加载
xmlns:xsi="http://w3.org/2001/XMLSchema-instance" xmlns:context="http://springframework.org/schema/context" xsi:schemaLocation=" http://springframework.org/schema/beans http://springframework.org/schema/beans/spring-beans-3.2.xsd http://springframework.org/schema/context http://springframework.org/schema/context/spring-context-3.2.xsd" default-lazy-init="true"> /sys/login = authc /sys/logout = logout /sys/** = user
xmlns:xsi="http://w3.org/2001/XMLSchema-instance" xmlns:context="http://springframework.org/schema/context"
xsi:schemaLocation="
http://springframework.org/schema/beans http://springframework.org/schema/beans/spring-beans-3.2.xsd
http://springframework.org/schema/context http://springframework.org/schema/context/spring-context-3.2.xsd"
default-lazy-init="true">
/sys/login = authc
/sys/logout = logout
/sys/** = user
新建一个登录认证过滤器FormAuthenticationFilter.java
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.web.util.WebUtils;
import org.springframework.stereotype.Service;
/**
* 表单验证(包含验证码)过滤类*/
@Service
public class FormAuthenticationFilter extends org.apache.shiro.web.filter.authc.FormAuthenticationFilter {
public static final String DEFAULT_CAPTCHA_PARAM = "validateCode";
private String captchaParam = DEFAULT_CAPTCHA_PARAM;
public String getCaptchaParam() {
return captchaParam;
}
protected String getCaptcha(ServletRequest request) {
return WebUtils.getCleanParam(request, getCaptchaParam());
}
protected AuthenticationToken createToken(ServletRequest request, ServletResponse response) {
String username = getUsername(request);
String password = getPassword(request);
String locale = request.getParameter("locale");
if (password == null) {
password = "";
}
boolean rememberMe = isRememberMe(request);
String host = getHost(request);
String captcha = getCaptcha(request);
return new UsernamePasswordToken(username, password.toCharArray(),locale, rememberMe, host, captcha);
}
}
新建令牌类UsernamePasswordToken.java
package com.chunhui.webservice.modules.sys.security;
/**
* 用户和密码(包含验证码)令牌类*/
public class UsernamePasswordToken extends org.apache.shiro.authc.UsernamePasswordToken {
private static final long serialVersionUID = 1L;
private String captcha;
private String locale;
public String getCaptcha() {
return captcha;
}
public void setCaptcha(String captcha) {
this.captcha = captcha;
}
public String getLocale() {
return locale;
}
public void setLocale(String locale) {
this.locale = locale;
}
public UsernamePasswordToken() {
super();
}
public UsernamePasswordToken(String username, char[] password, boolean rememberMe, String host, String captcha) {
super(username, password, rememberMe, host);
this.captcha = captcha;
}
public UsernamePasswordToken(String username, char[] password, String locale,boolean rememberMe, String host, String captcha) {
super(username, password, rememberMe, host);
this.captcha = captcha;
this.locale = locale;
}
}
最后一个是认证实现类SystemAuthorizationRealm:
package com.chunhui.webservice.modules.sys.security;
import java.io.Serializable;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.annotation.PostConstruct;
import com.chunhui.webservice.common.utils.EmployeeType;
import com.chunhui.webservice.common.utils.VertifyStatus;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.SimplePrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.springframework.context.annotation.DependsOn;
import org.springframework.stereotype.Service;
import com.chunhui.webservice.common.servlet.ValidateCodeServlet;
import com.chunhui.webservice.common.utils.SpringContextHolder;
import com.chunhui.webservice.modules.sys.entity.Employee;
import com.chunhui.webservice.modules.sys.entity.Menu;
import com.chunhui.webservice.modules.sys.service.SystemService;
import com.chunhui.webservice.modules.sys.utils.SystemUtils;
import com.chunhui.webservice.modules.sys.web.LoginController;
/**
* 系统安全认证实现类*/
@Service
@DependsOn({ "employeeDao", "roleDao", "menuDao" })
public class SystemAuthorizingRealm extends AuthorizingRealm {
private SystemService systemService;
/**
* 认证回调函数, 登录时调用
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) throws AuthenticationException {
UsernamePasswordToken token = (UsernamePasswordToken) authcToken;
// 判断验证码
Session session = SecurityUtils.getSubject().getSession();
// 设置独立的session会话超时时间 session.setTimeout(60000);
String code = (String) session.getAttribute(ValidateCodeServlet.VALIDATE_CODE);
if (token.getCaptcha() == null || !token.getCaptcha().toUpperCase().equals(code)) {
throw new CaptchaException("验证码错误!");
} //如果帐号不存在,输出
//throw new UnknownAccountException();
//如果帐号被禁用,输出
//throw new DisabledAccountException();
//保存登录时选择的语言
SecurityUtils.getSubject().getSession().setAttribute("locale", token.getLocale());
try{
SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(new Principal(employee), employee.getPassword(), getName());
return info;
}catch (Throwable t){
t.printStackTrace();
throw new AuthenticationException();
}
}/**
* 授权查询回调函数, 进行鉴权但缓存中无用户的授权信息时调用
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
Principal principal = (Principal) getAvailablePrincipal(principals);
Employee employee = getSystemService().getEmployeeByName(principal.getUsername());
if (employee != null) {
SystemUtils.putCache("employee", employee);
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
List
for (Menu menu : list) {
if (StringUtils.isNotBlank(menu.getPermission())) {
// 添加基于Permission的权限信息
for (String permission : StringUtils.split(menu.getPermission(), ",")) {
info.addStringPermission(permission);
}
}
}
// 更新登录IP和时间
getSystemService().updateEmployeeLoginInfo(employee.getId());
return info;
} else {
return null;
}
}
/**
* 清空用户关联权限认证,待下次使用时重新加载
*/
public void clearCachedAuthorizationInfo(String principal) {
SimplePrincipalCollection principals = new SimplePrincipalCollection(principal, getName());
clearCachedAuthorizationInfo(principals);
}
/**
* 清空所有关联认证
*/
public void clearAllCachedAuthorizationInfo() {
Cache
if (cache != null) {
for (Object key : cache.keys()) {
cache.remove(key);
}
}
}
/**
* 获取系统业务对象
*/
public SystemService getSystemService() {
if (systemService == null) {
systemService = SpringContextHolder.getBean(SystemService.class);
}
return systemService;
}
/**
* 授权用户信息
*/
public static class Principal implements Serializable {
private static final long serialVersionUID = 1L;
private String id;
private String username;
private String realname;
private Map
public Principal(Employee employee) {
this.id = employee.getId();
this.username = employee.getUsername();
this.realname = employee.getRealname();
}
public String getId() {
return id;
}
public String getUsername() {
return username;
}
public String getRealname() {
return realname;
}
public Map
if (cacheMap == null) {
cacheMap = new HashMap
}
return cacheMap;
}
}
}
那么在jsP页面,可以通过获取登录异常具体的异常类型来在页面显示错误原因
<%String error = (String) request.getAttribute(FormAuthenticationFilter.DEFAULT_ERROR_KEY_ATTRIBUTE_NAME);%>
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。
发表评论
暂时没有评论,来抢沙发吧~