Security3 安全架构 这里主要说的就是spring-security.xml 配置 因为网上这个资料确实很少
首先 pom
org.springframework.security 的包 我现在版本是3.1.4的 注意依赖都要导入的 包名就不写了!
web.xml
security 的过滤器链
springSecurityFilterChain
org.springframework.web.filter.DelegatingFilterProxy
springSecurityFilterChain
/*
现在开始正题
spring-security.xml 配置 这个配置主要是用来重写attemptAuthentication方法的 这个是重点
//UsernamePasswordAuthenticationFilter的实现 重写 attemptAuthentication方法 逻辑随意修改
package com.hearing.cloud.background.loginFilter;
import com.hearing.cloud.background.model.OrdinaryUser;
import com.hearing.cloud.background.model.User;
import com.hearing.cloud.background.service.IOrdinaryUserManager;
import com.hearing.cloud.background.service.IUserManager;
import com.hearing.cloud.background.util.ActionUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.authentication.encoding.ShaPasswordEncoder;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.authentication.session.NullAuthenticatedSessionStrategy;
import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy;
import org.springframework.util.Assert;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Map;
//这里一般都是继承UsernamePasswordAuthenticationFilter 但是 我这里没有继承他 我继承了他爷爷 AbstractAuthenticationProcessingFilter
public class LoginFilterAuthentication extends AbstractAuthenticationProcessingFilter {
public static final String SPRING_SECURITY_FORM_USERNAME_KEY = "j_username";
public static final String SPRING_SECURITY_FORM_PASSWORD_KEY = "j_password";
/** @deprecated */
@Deprecated
public static final String SPRING_SECURITY_LAST_USERNAME_KEY = "SPRING_SECURITY_LAST_USERNAME";
private String usernameParameter = "j_username";
private String passwordParameter = "j_password";
private boolean postOnly = true;
private SessionAuthenticationStrategy sessionStrategy = new NullAuthenticatedSessionStrategy();
//继承爷爷的原因是 我重新构造这个参数, 默认的是 /j_spring_security_check 我认为太丑
public LoginFilterAuthentication() {
super("/home");
}
@Autowired
private IOrdinaryUserManager ordinaryUserManager;
@Autowired
private IUserManager iUserManager;
@Autowired
private ShaPasswordEncoder shaPasswordEncoder;
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
if (this.postOnly &&!request.getMethod().equals("POST")) {
throw new AuthenticationServiceException(
"Authentication method not supported: " + request.getMethod());
}
UsernamePasswordAuthenticationToken authRequest=null;
//前端的选择,0是用户名登录, 1是验证码登录
Map map = ActionUtil.getParameters(request);
String selects=map.get("selects");
if("0".equals(selects)){ //正常登陆 因为我们没有在xml中配置加密,所以我们手动加密,更灵活一些
authRequest = new UsernamePasswordAuthenticationToken(账号, 密码);
}else{ //电话号码登录 密码就不用加密了 直接登录
//验证码对比结果
boolean falg=true;
if(falg) { //验证通过
authRequest = new UsernamePasswordAuthenticationToken(账号, 密码);
}else{//验证失败 我们要手动抛出一个异常,在后面的验证失败类中去捕获
authRequest = new UsernamePasswordAuthenticationToken("", "");
throw new AuthenticationServiceException("验证码错误");
}
request.getSession().removeAttribute("phone");
}
// Allow subclasses to set the "details" property
setDetails(request, authRequest);
// 执行校验(使用DaoAuthenticationProvider进行校验)
return this.getAuthenticationManager().authenticate(authRequest);
}
protected String obtainPassword(HttpServletRequest request) {
return request.getParameter(this.passwordParameter);
}
protected String obtainUsername(HttpServletRequest request) {
return request.getParameter(this.usernameParameter);
}
protected void setDetails(HttpServletRequest request, UsernamePasswordAuthenticationToken authRequest) {
authRequest.setDetails(this.authenticationDetailsSource.buildDetails(request));
}
public void setUsernameParameter(String usernameParameter) {
Assert.hasText(usernameParameter, "Username parameter must not be empty or null");
this.usernameParameter = usernameParameter;
}
public void setPasswordParameter(String passwordParameter) {
Assert.hasText(passwordParameter, "Password parameter must not be empty or null");
this.passwordParameter = passwordParameter;
}
public void setPostOnly(boolean postOnly) {
this.postOnly = postOnly;
}
}
//查询用户的实现 实现 UserDetailsService的 loadUserByUsername方法 返回一个UserDetails
@Repository(value = "userDaoImpl")
public class UserDaoImpl extends GenericDaoHibernate implements IUserDao, UserDetailsService {
/**
* 用户登录
*/
@SuppressWarnings({"deprecation", "rawtypes"})
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException
{
//逻辑我就不写了 你们想怎么写就怎么写,记得查询出来的 user 转换成 UserDetails
}
}
//验证成功的方法 需要继承SimpleUrlAuthenticationSuccessHandler和实现AuthenticationSuccessHandler接口
package com.hearing.cloud.background.loginFilter;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler;
import org.springframework.security.web.savedrequest.HttpSessionRequestCache;
import org.springframework.security.web.savedrequest.RequestCache;
import org.springframework.security.web.savedrequest.SavedRequest;
import org.springframework.util.StringUtils;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class LoginSuccessHandler extends SimpleUrlAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
//我重写的目的 1.主要是这个位置 因为我要访问我的 跳转首页方法的逻辑接口
//2.是如果不改这里 登录会有两个后果,1.登录后关闭页面,在次打开,页面会显示路径无法加载,2.
//第一次登录成功跳转页面是你首页加载的第一个js页面而不是首页,请认真对待
@Value("/")
private String defaultTargetUrl;
private RequestCache requestCache = new HttpSessionRequestCache();
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
SavedRequest savedRequest = this.requestCache.getRequest(request, response);
if(savedRequest == null) {
super.onAuthenticationSuccess(request, response, authentication);
} else {
String targetUrlParameter = this.getTargetUrlParameter();
if(!this.isAlwaysUseDefaultTargetUrl() && (targetUrlParameter == null || !StringUtils.hasText(request.getParameter(targetUrlParameter)))) {
this.clearAuthenticationAttributes(request);
this.logger.debug("Redirecting to DefaultSavedRequest Url: " + defaultTargetUrl);
this.getRedirectStrategy().sendRedirect(request, response, defaultTargetUrl);
} else {
this.requestCache.removeRequest(request, response);
super.onAuthenticationSuccess(request, response, authentication);
}
}
}
public void setRequestCache(RequestCache requestCache) {
this.requestCache = requestCache;
}
}
//验证失败 需要实现AuthenticationFailureHandler 接口
package com.hearing.cloud.background.loginFilter;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.DefaultRedirectStrategy;
import org.springframework.security.web.RedirectStrategy;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.util.UrlUtils;
import org.springframework.util.Assert;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
public class LoginFailureHandler implements AuthenticationFailureHandler {
private String defaultFailureUrl;
private boolean forwardToDestination = false;
private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
private boolean allowSessionCreation = true;
public LoginFailureHandler() {
}
public LoginFailureHandler(String defaultFailureUrl) {
this.setDefaultFailureUrl(defaultFailureUrl);
}
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) throws IOException, ServletException {
if(this.defaultFailureUrl == null) {
if("验证码错误".equals(e.getMessage())){
redirectStrategy.sendRedirect(request, response, "/doctorLogin?error=3");
}else{
redirectStrategy.sendRedirect(request, response, "/doctorLogin?error=1");
}
} else {
this.saveException(request, e);
if(this.forwardToDestination) {
request.getRequestDispatcher(this.defaultFailureUrl).forward(request, response);
} else {
this.redirectStrategy.sendRedirect(request, response, this.defaultFailureUrl);
}
}
}
public void setDefaultFailureUrl(String defaultFailureUrl) {
Assert.isTrue(UrlUtils.isValidRedirectUrl(defaultFailureUrl), "\'" + defaultFailureUrl + "\' is not a valid redirect URL");
this.defaultFailureUrl = defaultFailureUrl;
}
protected final void saveException(HttpServletRequest request, AuthenticationException exception) {
if(this.forwardToDestination) {
request.setAttribute("SPRING_SECURITY_LAST_EXCEPTION", exception);
} else {
HttpSession session = request.getSession(false);
if(session != null || this.allowSessionCreation) {
request.getSession().setAttribute("SPRING_SECURITY_LAST_EXCEPTION", exception);
}
}
}
protected boolean isUseForward() {
return this.forwardToDestination;
}
public void setUseForward(boolean forwardToDestination) {
this.forwardToDestination = forwardToDestination;
}
protected boolean isAllowSessionCreation() {
return this.allowSessionCreation;
}
public void setAllowSessionCreation(boolean allowSessionCreation) {
this.allowSessionCreation = allowSessionCreation;
}
}