springsecurity官网_log4j.properties配置

springsecurity官网_log4j.properties配置由于项目框架古老spring3.0springsecurity2.0.4,但功能齐全,所以个人想要升级各个jar包版本,以减少不必要的已知bug目标更换为springsecurity4.2springdata换为最新问题1:spring版本不匹配,jar包冲突这个是最好解决的,先把springsecurity做最基础配置,换几个理论上兼容的spring版本试试就行,最终选定…

大家好,又见面了,我是你们的朋友全栈君。

由于项目框架古老spring3.0 spring security2.0.4,但功能齐全,所以个人想要升级各个jar包版本,以减少不必要的已知bug

目标更换为spring security4.2 spring data换为最新

问题1:spring版本不匹配,jar包冲突

这个是最好解决的,先把spring security做最基础配置,换几个理论上兼容的spring版本试试就行,最终选定spring 4.3.18,

较为稳定且各方面都满足需求,耗时10分钟

问题2:项目需实现3种角色4种版本登录,网上相关文章不多且大多是基本配置,无法达到项目需要

只能自己一步一步摸索,总共写了29个demo,各种冲突bug应有尽有,网上的各种配置排除重复的几乎也试了个遍,要么用不上要么功能不全,最终把多篇文章终于组合完成,自定义了loginFilter 以及权限filter,能够实现各个权限的随意配置,因项目需要未做分组管理角色,角色与各权限几乎是一对一

<http pattern="/**/login.*" security="none"/>
    <http pattern="/**/login_error.*" security="none"/>
    <http pattern="/**/error.*" security="none"/>
    <http pattern="/download/**" security="none"/>
    <http pattern="/resources/**" security="none"/>
    <http pattern="/upload/**" security="none"/>
    <http pattern="/**/register.do" security="none"/>
    <http pattern="/verify/**" security="none"/>
    <global-method-security secured-annotations="enabled"/>
    <http  auto-config="false" use-expressions="true" entry-point-ref="loginEntryPoint">
        <!-- 禁用CSRF保护,默认是启用 -->
        <csrf disabled="true"/>
        <headers disabled="true"/>
        <!--匿名者-->
        <anonymous enabled="false"/>
        <!-- 路径所需角色认证 hasRole 包含某个角色 hasAuthority包含某个权限-->
        <intercept-url pattern="/admin/**" access="hasAuthority('admin_index')"/>
        <intercept-url pattern="/seller/**" access="hasAuthority('seller_index')"/>
        <!--<intercept-url pattern="/**" access="authenticated"/>-->
        <logout logout-success-url="/login.do" logout-url="/loginout.do" delete-cookies="JSESSIONID"/>
        <!--session管理-->
        <custom-filter ref="concurrencyFilter" position="CONCURRENT_SESSION_FILTER"/>
        <!--登录验证-->
        <custom-filter ref="loginFilter" position="FORM_LOGIN_FILTER"/>
        <!--权限验证-->
        <custom-filter ref="myFilter" before="FILTER_SECURITY_INTERCEPTOR"/>
    </http>

自定义了各个链接地址以及跳转url

<beans:bean id="myFilter" class="com.www.common.security.SecurityInterceptor">
        <!--登录验证-->
        <beans:property name="authenticationManager" ref="authenticationManager"/>
        <!--权限验证-->
        <beans:property name="accessDecisionManager" ref="myAccessDecisionManagerBean"/>
        <!--访问的url资源权限信息-->
        <beans:property name="securityMetadataSource" ref="securityMetadataSource"/>
    </beans:bean>
<!-- md5 -->
    <beans:bean id="passwordEncoder" class="com.www.common.utils.MD5"/>
    <!-- 在这个类中,读入用户的密码,角色信息,是否锁定,账号是否过期等属性信息  -->
    <beans:bean id="myUserDetailService" class="com.www.common.security.MyUserDetailService"/>
    <!-- 访问决策器,决定某个用户具有的角色,是否有足够的权限去访问某个资源 -->
    <beans:bean id="myAccessDecisionManagerBean" class="com.www.common.security.DecisionManager"/>
    <!-- 资源源数据定义,即定义某一资源可以被哪些角色访问 -->
    <beans:bean id="securityMetadataSource" class="com.www.common.security.SecurityMetadataSource"/>
    <!--session会话创建销毁-->
    <beans:bean id="sessionRegistry" class="org.springframework.security.core.session.SessionRegistryImpl"/>
    <!-- 登录页面 -->
    <beans:bean id="loginEntryPoint" class="com.www.common.security.LoginEntryPoint">
        <beans:constructor-arg name="loginFormUrl" value="/login.do"/>
    </beans:bean>
    <!--登录失败跳转页面,如需不使用页面返回可重写此类-->
    <beans:bean id="loginFailureHandler" class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler">
        <beans:property name="defaultFailureUrl" value="/login_error.do"/>
    </beans:bean>
    <!--登录成功跳转的页面-->
    <beans:bean id="loginSuccessHandler" class="com.www.common.security.SuccessHandler">
        <beans:property name="defaultTargetUrl" value="/index.do"/>
    </beans:bean>
package com.www.common.security;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.access.AccessDecisionManager;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.authentication.InsufficientAuthenticationException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;

import java.util.Collection;
import java.util.Iterator;

/**
 * 访问决策器
 * 决定某个用户具有的角色
 * 是否有足够的权限去访问某个资源
 *  在这种方法中,需要与configAttributes比较验证
 * 1、一个对象是一个URL,一个过滤器被这个URL找到权限配置,并通过这里
 * 2、如果没有匹配相应的认证,AccessDeniedException
 * @author 
 */
public class DecisionManager implements AccessDecisionManager {

	private Logger log= LoggerFactory.getLogger(DecisionManager.class);
	/**
	 * 在这个类中,最重要的是decide方法,如果不存在对该资源的定义,直接放行
	 * 否则,如果找到正确的角色,即认为拥有权限,并放行,
	 * 否则throw new AccessDeniedException("no right");
	 * 这样,就会进入上面提到的/accessDenied.jsp页面。
	 * @param authentication :当前用户所有的角色
	 * @param object :当前请求的URL
	 * @param configAttributes :当前URL所需要的角色
	 */
	@Override
	public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes) throws AccessDeniedException, InsufficientAuthenticationException {
		// 资源所需的角色列表,如果角色列表为空,则放行!继续下一个拦截器。
		if (configAttributes == null) {
			return;
		}
		log.info("%%%%%authentication :"+authentication.toString());
		log.info("&&&&&configAttributes :"+configAttributes.toString());
		// 即将访问的资源URL,如 : /admin.jsp
		log.info("URL :"+object);
		// 遍历所需的角色集合
		Iterator<ConfigAttribute> ite = configAttributes.iterator();
		while (ite.hasNext()) {
			ConfigAttribute ca = ite.next();
			// 该资源所需要的角色
			String needRole = ca.getAttribute();
			// authentication.getAuthorities()获取用户所拥有的角色列表,如:OLE_DEFULT
			for (GrantedAuthority grantedAuthority : authentication.getAuthorities()) {
				// 将资源所需要的角色与用户拥有的角色比较
				if (needRole.equals(grantedAuthority.getAuthority())) {
					// 角色相同,直接放行
					return;
				}
			}
		}
		// 否则,提示没有权限访问该资源
		throw new AccessDeniedException("no right");
	}

	@Override
	public boolean supports(ConfigAttribute attribute) {
		return true;
	}

	@Override
	public boolean supports(Class<?> clazz) {
		return true;
	}
}
package com.www.common.security;

import com.www.common.enums.Constant;
import com.www.common.enums.RoleType;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.*;
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
import org.springframework.security.web.util.RedirectUrlBuilder;
import org.springframework.security.web.util.UrlUtils;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
  *	访问资源无权限时访问
 * @Author: zhouchaoxi
 * @Date: Created in 2018/7/7 0:13
 * @Modified By: 
 */
public class LoginEntryPoint implements AuthenticationEntryPoint,InitializingBean {

	private PortMapper portMapper = new PortMapperImpl();

	private PortResolver portResolver = new PortResolverImpl();

	private String loginFormUrl;

	private boolean forceHttps = false;

	private boolean useForward = false;

	private final RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();

	public LoginEntryPoint(String loginFormUrl) {
		Assert.notNull(loginFormUrl, "loginFormUrl cannot be null");
		this.loginFormUrl = loginFormUrl;
	}
	/**
	 * Performs the redirect (or forward) to the login form URL.
	 */
	public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
		String redirectUrl = null;
		String returnUrl = buildHttpReturnUrlForRequest(request);
		System.out.println("========"+returnUrl+"========");
		if (returnUrl.contains("/admin/")){
			request.getSession().setAttribute(Constant.LOGIN_ROLE, RoleType.ADMIN());
			this.loginFormUrl="/admin/login.do";
		}else{
			request.getSession().setAttribute(Constant.LOGIN_ROLE, RoleType.USER());
		}
		if (useForward) {
			if (forceHttps && "http".equals(request.getScheme())) {
				redirectUrl = buildHttpsRedirectUrlForRequest(request);
			}
			if (redirectUrl == null) {
				String loginForm = determineUrlToUseForThisRequest(request, response, authException);
				RequestDispatcher dispatcher = request.getRequestDispatcher(loginForm);
				dispatcher.forward(request, response);
				return;
			}
		} else {
			redirectUrl = buildRedirectUrlToLoginPage(request, response, authException);
		}
		redirectStrategy.sendRedirect(request, response, redirectUrl);
	}

	protected String buildHttpReturnUrlForRequest(HttpServletRequest request) throws IOException, ServletException {
		RedirectUrlBuilder urlBuilder = new RedirectUrlBuilder();
		urlBuilder.setScheme("http");
		urlBuilder.setServerName(request.getServerName());
		urlBuilder.setPort(request.getServerPort());
		urlBuilder.setContextPath(request.getContextPath());
		urlBuilder.setServletPath(request.getServletPath());
		urlBuilder.setPathInfo(request.getPathInfo());
		urlBuilder.setQuery(request.getQueryString());
		return urlBuilder.getUrl();
	}

	public void afterPropertiesSet() throws Exception {
		Assert.isTrue(StringUtils.hasText(loginFormUrl) && UrlUtils.isValidRedirectUrl(loginFormUrl),
				"loginFormUrl must be specified and must be a valid redirect URL");
		if (useForward && UrlUtils.isAbsoluteUrl(loginFormUrl)) {
			throw new IllegalArgumentException("useForward must be false if using an absolute loginFormURL");
		}
		Assert.notNull(portMapper, "portMapper must be specified");
		Assert.notNull(portResolver, "portResolver must be specified");
	}

	/**
	 * Allows subclasses to modify the login form URL that should be applicable for a
	 * given request.
	 *
	 * @param request the request
	 * @param response the response
	 * @param exception the exception
	 * @return the URL (cannot be null or empty; defaults to {@link #getLoginFormUrl()})
	 */
	protected String determineUrlToUseForThisRequest(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) {
		return getLoginFormUrl();
	}

	protected String buildRedirectUrlToLoginPage(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) {
		String loginForm = determineUrlToUseForThisRequest(request, response, authException);
		if (UrlUtils.isAbsoluteUrl(loginForm)) {
			return loginForm;
		}
		int serverPort = portResolver.getServerPort(request);
		String scheme = request.getScheme();
		RedirectUrlBuilder urlBuilder = new RedirectUrlBuilder();

		urlBuilder.setScheme(scheme);
		urlBuilder.setServerName(request.getServerName());
		urlBuilder.setPort(serverPort);
		urlBuilder.setContextPath(request.getContextPath());
		urlBuilder.setPathInfo(loginForm);

		if (forceHttps && "http".equals(scheme)) {
			Integer httpsPort = portMapper.lookupHttpsPort(Integer.valueOf(serverPort));
			if (httpsPort != null) {
				// Overwrite scheme and port in the redirect URL
				urlBuilder.setScheme("https");
				urlBuilder.setPort(httpsPort.intValue());
			}
			else {
			}
		}
		return urlBuilder.getUrl();
	}

	/**
	 * Builds a URL to redirect the supplied request to HTTPS. Used to redirect the
	 * current request to HTTPS, before doing a forward to the login page.
	 */
	protected String buildHttpsRedirectUrlForRequest(HttpServletRequest request) throws IOException, ServletException {
		int serverPort = portResolver.getServerPort(request);
		Integer httpsPort = portMapper.lookupHttpsPort(Integer.valueOf(serverPort));
		if (httpsPort != null) {
			RedirectUrlBuilder urlBuilder = new RedirectUrlBuilder();
			urlBuilder.setScheme("https");
			urlBuilder.setServerName(request.getServerName());
			urlBuilder.setPort(httpsPort.intValue());
			urlBuilder.setContextPath(request.getContextPath());
			urlBuilder.setServletPath(request.getServletPath());
			urlBuilder.setPathInfo(request.getPathInfo());
			urlBuilder.setQuery(request.getQueryString());

			return urlBuilder.getUrl();
		}
		return null;
	}

	/**
	 * Set to true to force login form access to be via https. If this value is true (the
	 * default is false), and the incoming request for the protected resource which
	 * triggered the interceptor was not already <code>https</code>, then the client will
	 * first be redirected to an https URL, even if <tt>serverSideRedirect</tt> is set to
	 * <tt>true</tt>.
	 */
	public void setForceHttps(boolean forceHttps) {
		this.forceHttps = forceHttps;
	}

	protected boolean isForceHttps() {
		return forceHttps;
	}

	public String getLoginFormUrl() {
		return loginFormUrl;
	}

	public void setPortMapper(PortMapper portMapper) {
		Assert.notNull(portMapper, "portMapper cannot be null");
		this.portMapper = portMapper;
	}

	protected PortMapper getPortMapper() {
		return portMapper;
	}

	public void setPortResolver(PortResolver portResolver) {
		Assert.notNull(portResolver, "portResolver cannot be null");
		this.portResolver = portResolver;
	}

	protected PortResolver getPortResolver() {
		return portResolver;
	}

	/**
	 * Tells if we are to do a forward to the {@code loginFormUrl} using the
	 * {@code RequestDispatcher}, instead of a 302 redirect.
	 *
	 * @param useForward true if a forward to the login page should be used. Must be false
	 * (the default) if {@code loginFormUrl} is set to an absolute value.
	 */
	public void setUseForward(boolean useForward) {
		this.useForward = useForward;
	}

	protected boolean isUseForward() {
		return useForward;
	}
}
package com.www.common.security;

import com.www.common.enums.Constant;
import com.www.common.utils.Const;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.util.Assert;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * @描述:
 * @作者: zhouChaoXi
 * @时间: 2018/7/3 21:20
 */
public class LoginFromFilter extends UsernamePasswordAuthenticationFilter{

    public static final String SPRING_SECURITY_FORM_VALID_CODE = "code";
    private String codeParameter = SPRING_SECURITY_FORM_VALID_CODE;

    public LoginFromFilter() {
        super();
    }

    /**
     * 如果是通过页面进来验证码效验
     * 非页面进入不效验
      * 并拼接用户名和登录角色
     * @Author: zhouchaoxi
     * @Date: Created in 2018/8/4 17:44
     * @Modified By: 
     */
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
        String  code = (String)request.getSession().getAttribute(Constant.CODE);
        String  inputCode = obtainValidCode(request);
        String login_role=request.getParameter(Constant.LOGIN_ROLE);
        request.getSession().setAttribute(Constant.LOGIN_ROLE,login_role);
        String username=obtainUsername(request);
        String password=obtainPassword(request);
        if (username == null)username = "";
        if (password == null)password = "";
        username=username+"__"+login_role;
        username = username.trim();
        UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password);
        setDetails(request, authRequest);
        if (code==null){
            return super.getAuthenticationManager().authenticate(authRequest);
        }else if(code.toUpperCase().equals(inputCode.toUpperCase())){
            return super.getAuthenticationManager().authenticate(authRequest);
        }else{
            throw new AuthenticationServiceException("验证码输入错误");
        }

    }

    protected String obtainValidCode(HttpServletRequest request) {
        return request.getParameter(codeParameter);
    }

    public String getCodeParameter() {
        return codeParameter;
    }

    public void setCodeParameter(String codeParameter) {
        Assert.hasText(codeParameter, "Valid code parameter must not be empty or null");
        this.codeParameter = codeParameter;
    }

}
package com.www.common.security;

import com.www.common.enums.RoleType;
import com.www.common.pojo.User;
import com.www.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;

/**
 * 从数据库中读入用户的密码
 * 角色信息,是否锁定,账号是否过期等
 * @author 
 */
public class MyUserDetailService implements UserDetailsService {


	@Autowired
	private UserService userService;

	@Override
	public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
		String[] usernameList=username.split("__");
		String userName="";
		String login_role= RoleType.USER();
		if (usernameList.length>1){
			for(int i=0;i<usernameList.length-1;i++)userName+=usernameList[i];
			login_role="%"+usernameList[usernameList.length-1]+"%";
		}
		User user=this.userService.getObjByRoleAndName(userName,login_role);
		if(user!=null){
//			List<GrantedAuthority> auths = new ArrayList<GrantedAuthority>();
//			String roles=user.getUserRole();
//			if (!CommUtil.isNull(roles)){
//				String[] role=roles.split(",");
//				for (String auth:role){
//					auths.add(new SimpleGrantedAuthority(auth));
//				}
//			}
//			User userDetails = new User(username, user.getPassword(), true, true, true, true, auths);
			return  user;
		}
		throw new UsernameNotFoundException("UserName " + username + " not found");
	}


}
package com.www.common.security;

import org.springframework.security.access.SecurityMetadataSource;
import org.springframework.security.access.intercept.AbstractSecurityInterceptor;
import org.springframework.security.access.intercept.InterceptorStatusToken;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;

import javax.servlet.*;
import java.io.IOException;

/**
 * 拦截器核心
 */
public class SecurityInterceptor extends AbstractSecurityInterceptor implements Filter {

	private FilterInvocationSecurityMetadataSource securityMetadataSource;

	@Override
	public void init(FilterConfig filterConfig){

	}
	@Override
	public void destroy() {

	}

	@Override
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
		FilterInvocation fi = new FilterInvocation(request, response, chain);
		invoke(fi);
	}

	public void invoke(FilterInvocation fi) throws IOException, ServletException {
		/**
		 * 最核心的代码就是@link InterceptorStatusToken token = super.beforeInvocation(fi);
		 * 它会调用我们定义的MyInvocationSecurityMetadataSource.getAttributes方法和MyAccessDecisionManager.decide方法
		 * 这一句,即在执行doFilter之前,进行权限的检查,而具体的实现已经交给@link DecisionManager 了
		 */
		InterceptorStatusToken token = super.beforeInvocation(fi);
		try {
			//继续走下一个拦截器,也就是org.springframework.security.web.access.intercept.FilterSecurityInterceptor
			fi.getChain().doFilter(fi.getRequest(), fi.getResponse());
		} finally {
			super.afterInvocation(token, null);
		}
	}

	@Override
	public Class<?> getSecureObjectClass() {
		return FilterInvocation.class;
	}

	@Override
	public SecurityMetadataSource obtainSecurityMetadataSource() {
		return this.securityMetadataSource;
	}

	public FilterInvocationSecurityMetadataSource getSecurityMetadataSource() {
		return securityMetadataSource;
	}

	public void setSecurityMetadataSource(FilterInvocationSecurityMetadataSource securityMetadataSource) {
		this.securityMetadataSource = securityMetadataSource;
	}
}
package com.www.common.security;

import com.www.service.ResService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;

import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 定义某一资源可以被哪些角色访问
 * @author 
 */
public class SecurityMetadataSource implements FilterInvocationSecurityMetadataSource,InitializingBean{

	private Logger log= LoggerFactory.getLogger(SecurityMetadataSource.class);
	private static HashMap<String,List<ConfigAttribute>> allResource;
	@Autowired
	private ResService resService;
	@Override
	public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException {
		FilterInvocation fi = (FilterInvocation) object;
//		访问的路径
		String requestUrl = fi.getRequest().getRequestURI();
		List<ConfigAttribute> attributes = new ArrayList<ConfigAttribute>();
		// 所有URL对应的角色,应用启动就存放到静态资源里,得到的结果是:不同的URL下,包含的多个角色
		HashMap<String,List<ConfigAttribute>> resRoles = allResource;
		if(!resRoles.isEmpty()){
			for (Map.Entry<String, List<ConfigAttribute>> ent : resRoles.entrySet()) {
//				需要验证的url
				String url = ent.getKey();
				List<ConfigAttribute> roles = ent.getValue();
				//根据业务写自己的匹配逻辑
				if(url!=null&&requestUrl.contains(url)){
					attributes=roles;
				}
			}
		}
		log.debug("【"+fi.getRequest().getRequestURI()+"】 roles: "+attributes);
		return attributes;
	}

	@Override
	public Collection<ConfigAttribute> getAllConfigAttributes() {
		return null;
	}

	@Override
	public boolean supports(Class<?> clazz) {
		return FilterInvocation.class.isAssignableFrom(clazz);
	}

	@Override
	public void afterPropertiesSet() throws Exception {
		loadResourceDefine();
	}

	private void loadResourceDefine() {
		if(allResource == null) {
			allResource = new HashMap<>();
		}else{
			allResource.clear();
		}
		Map<String,List<String>> resourceRoleMap = resService.getAllResourceRole();
		for (Map.Entry<String,List<String>> entry : resourceRoleMap.entrySet()) {
//          需要权限的url
			String url = entry.getKey();
//          可以访问此url的角色
			List<String> values = entry.getValue();
			List<ConfigAttribute> configAttributes = new ArrayList<ConfigAttribute>();
			for(String role : values){
				configAttributes.add(new SecurityConfig(role));
			}
			allResource.put(url, configAttributes);
		}
	}
}
package com.www.common.security;

import com.www.common.pojo.User;
import com.www.common.utils.CommUtil;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

public class SecurityUserHolder {

    public static User getCurrentUser() {
        if (SecurityContextHolder.getContext().getAuthentication() != null) {
            if ((SecurityContextHolder.getContext().getAuthentication().getPrincipal() instanceof User)) {
                return (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
            }
        }
        User user = null;
        if (RequestContextHolder.getRequestAttributes() != null) {
            HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
            HttpSession session = request.getSession(false);
            if (session != null)
                user = session.getAttribute("user") != null ? (User) session.getAttribute("user") : null;

        }
        return user;
    }
}

package com.www.common.security;

import com.www.common.enums.Constant;
import com.www.common.enums.RoleType;
import com.www.common.pojo.UserConfig;
import com.www.common.utils.CommUtil;
import com.www.service.UserConfigService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Date;

/**
 * 权限验证成功
 * @author 
 */
public class SuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler {

    @Autowired
    private UserConfigService userConfigService;
    private Logger log= LoggerFactory.getLogger(SuccessHandler.class);
    /**
      *登录成功后的操作
     * @Author: zhouchaoxi
     * @Date: Created in 2018/8/4 18:24
     * @Modified By: 
     */
    @Override
    public void onAuthenticationSuccess(HttpServletRequest req, HttpServletResponse rep, Authentication auths) throws IOException, ServletException {
        System.out.println("=========================登录成功==============================");
        String s = "\n"+
                "                   _ooOoo_"+"\n"+
                "                  o8888888o"+"\n"+
                "                  88\" . \"88"+"\n"+
                "                  (| -_- |)"+"\n"+
                "                   O\\ = /O"+"\n"+
                "               ____/`---'\\____"+"\n"+
                "                . ' \\| |// `."+"\n"+
                "              / \\\\||| : |||// \\"+"\n"+
                "            / _||||| -:- |||||- \\"+"\n"+
                "             | | | \\\\\\ - /// | |"+"\n"+
                "             | \\_| ''\\---/'' | |"+"\n"+
                "             \\ .-\\__ `-` ___/-. /"+"\n"+
                "           ___\"`. .' /--.--\\ `. . __"+"\n"+
                "        .\"\" '< `.___\\_<|>_/___.' >'\"\"."+"\n"+
                "       | | : `- \\`.;`\\ _ /`;.`/ - ` : | |"+"\n"+
                "         \\ \\ `-. \\_ __\\ /__ _/ .-` / /"+"\n"+
                " ======`-.____`-.___\\_____/___.-`____.-'======";
        log.info(s);
        clearAuthenticationAttributes(req);
        String targetUrl = "/index.do";
//       根据登录角色不同跳转不同页面
        String role= (String) req.getSession().getAttribute(Constant.LOGIN_ROLE);
        req.getSession().removeAttribute(Constant.CODE);
        if (RoleType.ADMIN().equals(role)){
            targetUrl="/admin/index.do";
        }else if (RoleType.SELLER().equals(role)){
            targetUrl="/seller/index.do";
        }
        UserConfig config=userConfigService.getObjectById(SecurityUserHolder.getCurrentUser().getId());
        config.setLoginCount(config.getLoginCount()+1);
        config.setLoginDate(new Date());
        config.setLoginIp(CommUtil.getIpAddr(req));
        userConfigService.save(config);
        getRedirectStrategy().sendRedirect(req, rep, targetUrl);
    }
}

spring的配置相对简单就不赘述,都是基本配置,后面附完整的xml,耗时3小时

问题3:配置完自定义过后配置maxsession失效,单点登录功能丧失,网上找了n篇文章,n套美其名曰完整项目的配置都不生效

进源码debug登录成功始终不进registernewsession方法,又去网上找了半天也没有合适的,于是决定自己研究,把security所可能用到的方法打上debug,登录成功一步一步过,查看官方文档说明找到了问题所在,SessionAuthenticationStrategy:该接口中存在onAuthentication方法用于对新登录用户进行session相关的校验。查看UsernamePasswordAuthenticationFilter及其父类代码,可以发现在doFilter中存在sessionStrategy.onAuthentication(authResult, request, response);方法
但UsernamePasswordAuthenticationFilter中的sessionStrategy对象默认为NullAuthenticatedSessionStrategy,即不对session进行相关验证。
去掉通用的maxsession配置,加入sessionfilter,注入sessionStrategy

测试2个浏览器登录,OK,我去一个简单的配置找遍了网上也没有。。。。

这就郁闷了,所以才有了本文

整理完过后的完整xml如下,因为不需要记住密码功能,所以本项目没有加入,需要加入配置一个remberme就好了,那个相对简单

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>SSH</groupId>
<artifactId>SSH</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<name>SSH</name>
<description/>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<spring.version>4.3.18.RELEASE</spring.version>
<hibernate.version>5.0.12.Final</hibernate.version>
</properties>
<dependencies>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<version>7.0</version>
<scope>provided</scope>
</dependency>
<!-- =============spring================ -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<!--<dependency>-->
<!--<groupId>org.springframework</groupId>-->
<!--<artifactId>spring-test</artifactId>-->
<!--<version>${spring.version}</version>-->
<!--</dependency>-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- ====spring ===end===================================== -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.10</version>
</dependency>
<!-- ====druid ===end===================================== -->
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache-core</artifactId>
<version>2.6.11</version>
</dependency>
<!-- ====ehcache ===end===================================== -->
<!-- ====json===start============================================== -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.5</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.5</version>
</dependency>
<!-- ====json===end============================================== -->
<!-- =====aspectj===start=============================================== -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.8.5</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.5</version>
</dependency>
<!-- =====aspectj===end=============================================== -->
<!-- ======hibernate==start======================================= -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>${hibernate.version}</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>${hibernate.version}</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-ehcache</artifactId>
<version>${hibernate.version}</version>
</dependency>
<!-- ====hibernate==end=================================== -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
<version>1.10.11.RELEASE</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.46</version>
</dependency>
<dependency>
<groupId>com.alipay.sdk</groupId>
<artifactId>alipay-sdk-java</artifactId>
<version>3.3.4.ALL</version>
</dependency>
<dependency>
<groupId>com.github.binarywang</groupId>
<artifactId>weixin-java-pay</artifactId>
<version>3.1.1.BETA</version>
</dependency>
<!--<dependency>-->
<!--<groupId>cn.jpush.api</groupId>-->
<!--<artifactId>jpush-client</artifactId>-->
<!--<version>3.3.7</version>-->
<!--</dependency>-->
<!--<dependency>-->
<!--<groupId>cn.jpush.api</groupId>-->
<!--<artifactId>jiguang-common</artifactId>-->
<!--<version>1.1.1</version>-->
<!--</dependency>-->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>3.6</version>
</dependency>
<!-- ======slf4j==================== -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.25</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.25</version>
</dependency>
<!-- =====log4j2============================= -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.10.0</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-jcl</artifactId>
<version>2.10.0</version>
</dependency>
<!-- ====commons帮助包=================================== -->
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.6</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.11</version>
</dependency>
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>1.9.3</version>
</dependency>
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.3</version>
</dependency>
<dependency>
<groupId>jdom</groupId>
<artifactId>jdom</artifactId>
<version>1.1</version>
</dependency>
<dependency>
<groupId>dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>1.6.1</version>
</dependency>
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.3.0</version>
</dependency>
<!-- ===velocity================================ -->
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity</artifactId>
<version>1.7</version>
</dependency>
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-tools</artifactId>
<version>2.0</version>
</dependency>
<!-- security========================== -->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
<version>4.2.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>4.2.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>4.2.7.RELEASE</version>
</dependency>
<!--又拍云-->
<dependency>
<groupId>com.upyun</groupId>
<artifactId>java-sdk</artifactId>
<version>4.0.1</version>
</dependency>
<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>core</artifactId>
<version>3.3.3</version>
</dependency>
<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>javase</artifactId>
<version>3.3.3</version>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.6</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpcore</artifactId>
<version>4.4.10</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpmime</artifactId>
<version>4.5.6</version>
</dependency>
<dependency>
<groupId>commons-httpclient</groupId>
<artifactId>commons-httpclient</artifactId>
<version>3.1</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>2.2</version>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin>
</plugins>
</build>
</project>

 

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/mvc 
http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
http://www.springframework.org/schema/beans 
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context 
http://www.springframework.org/schema/context/spring-context-4.0.xsd">
<!-- 配置自动扫描的包 -->
<context:component-scan base-package="com.www.controller"/>
<context:annotation-config/>
<mvc:annotation-driven/>
<!-- 对模型视图名称的解析,即在模型视图名称添加前后缀 -->
<bean id="velocityCongfig" class="org.springframework.web.servlet.view.velocity.VelocityConfigurer">
<!-- velocity配置文件路径  或者直接用velocityProperties属性 -->
<property name="configLocation" value="classpath:config/velocity.properties"/>
<!-- velocity模板路径 -->
<property name="resourceLoaderPath" value="/WEB-INF/templates/zh_jd/"/>
</bean>
<bean id="viewResolver" class="org.springframework.web.servlet.view.velocity.VelocityViewResolver">
<property name="contentType" value="text/html;charset=UTF-8"/>
<property name="suffix" value=".html"/>
<property name="exposeSpringMacroHelpers" value="true" /><!--是否使用spring对宏定义的支持-->
<property name="exposeSessionAttributes" value="true" /><!--是否开放request属性-->
<property name="requestContextAttribute" value="request"/><!--request属性引用名称-->
<property name="dateToolAttribute" value="dateTool"/>
<property name="numberToolAttribute" value="numberTool"/>
</bean>
</beans>
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-4.2.xsd">
<!--<debug/>-->
<http pattern="/**/login.*" security="none"/>
<http pattern="/**/login_error.*" security="none"/>
<http pattern="/**/error.*" security="none"/>
<http pattern="/download/**" security="none"/>
<http pattern="/resources/**" security="none"/>
<http pattern="/upload/**" security="none"/>
<http pattern="/**/register.do" security="none"/>
<http pattern="/verify/**" security="none"/>
<global-method-security secured-annotations="enabled"/>
<http  auto-config="false" use-expressions="true" entry-point-ref="loginEntryPoint">
<!-- 禁用CSRF保护,默认是启用 -->
<csrf disabled="true"/>
<headers disabled="true"/>
<!--匿名者-->
<anonymous enabled="false"/>
<!-- 路径所需角色认证 hasRole 包含某个角色 hasAuthority包含某个权限-->
<intercept-url pattern="/admin/**" access="hasAuthority('admin_index')"/>
<intercept-url pattern="/seller/**" access="hasAuthority('seller_index')"/>
<!--<intercept-url pattern="/**" access="authenticated"/>-->
<logout logout-success-url="/login.do" logout-url="/loginout.do" delete-cookies="JSESSIONID"/>
<!--session管理-->
<custom-filter ref="concurrencyFilter" position="CONCURRENT_SESSION_FILTER"/>
<!--登录验证-->
<custom-filter ref="loginFilter" position="FORM_LOGIN_FILTER"/>
<!--权限验证-->
<custom-filter ref="myFilter" before="FILTER_SECURITY_INTERCEPTOR"/>
</http>
<beans:bean id="loginFilter" class="com.www.common.security.LoginFromFilter">
<!-- 登录提交处理 -->
<beans:property name="filterProcessesUrl" value="/shopping_login.do"/>
<!-- 登录成功跳转 -->
<beans:property name="authenticationSuccessHandler" ref="loginSuccessHandler"/>
<!-- 设置登录失败的网址 -->
<beans:property name="authenticationFailureHandler" ref="loginFailureHandler"/>
<!-- 用户拥有权限 -->
<beans:property name="authenticationManager" ref="authenticationManager"/>
<!--在线人数管理,不配置为NullAuthenticatedSessionStrategy不再进行session验证-->
<beans:property name="sessionAuthenticationStrategy" ref="sessionStrategy"/>
<!--登录页面参数-->
<beans:property name="usernameParameter" value="username"/>
<beans:property name="passwordParameter" value="password"/>
<beans:property name="codeParameter" value="code"/>
</beans:bean>
<!-- 权限认证Spring日志监听器  -->
<beans:bean class="org.springframework.security.authentication.event.LoggerListener"/>
<beans:bean class="org.springframework.security.access.event.LoggerListener"/>
<beans:bean id="myFilter" class="com.www.common.security.SecurityInterceptor">
<!--登录验证-->
<beans:property name="authenticationManager" ref="authenticationManager"/>
<!--权限验证-->
<beans:property name="accessDecisionManager" ref="myAccessDecisionManagerBean"/>
<!--访问的url资源权限信息-->
<beans:property name="securityMetadataSource" ref="securityMetadataSource"/>
</beans:bean>
<!-- 验证配置,实现用户认证的入口,主要实现UserDetailsService接口即可  -->
<authentication-manager alias="authenticationManager">
<authentication-provider ref="myAuthenticationProvider"/>
</authentication-manager>
<!--用户登录验证配置和加密方式-->
<beans:bean id="myAuthenticationProvider" class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
<beans:property name="userDetailsService" ref="myUserDetailService" />
<beans:property name="passwordEncoder" ref="passwordEncoder" />
</beans:bean>
<!--session会话总控制-->
<beans:bean id="concurrencyFilter" class="org.springframework.security.web.session.ConcurrentSessionFilter">
<beans:constructor-arg name="sessionRegistry" ref="sessionRegistry"/>
<beans:constructor-arg name="sessionInformationExpiredStrategy" ref="expiredStrategy"/>
</beans:bean>
<!--基于onAuthentication方法的代理-->
<beans:bean id="sessionStrategy" class="org.springframework.security.web.authentication.session.CompositeSessionAuthenticationStrategy">
<beans:constructor-arg>
<beans:list>
<beans:bean class="org.springframework.security.web.authentication.session.ConcurrentSessionControlAuthenticationStrategy">
<beans:constructor-arg ref="sessionRegistry"/>
<!-- 这里是配置session数量,此处为1,表示同一个用户同时只会有一个session在线 -->
<beans:property name="maximumSessions" value="1" />
<beans:property name="exceptionIfMaximumExceeded" value="false"/>
</beans:bean>
<beans:bean class="org.springframework.security.web.authentication.session.SessionFixationProtectionStrategy"/>
<beans:bean class="org.springframework.security.web.authentication.session.RegisterSessionAuthenticationStrategy">
<beans:constructor-arg ref="sessionRegistry"/>
</beans:bean>
</beans:list>
</beans:constructor-arg>
</beans:bean>
<!-- md5 -->
<beans:bean id="passwordEncoder" class="com.www.common.utils.MD5"/>
<!-- 在这个类中,读入用户的密码,角色信息,是否锁定,账号是否过期等属性信息  -->
<beans:bean id="myUserDetailService" class="com.www.common.security.MyUserDetailService"/>
<!-- 访问决策器,决定某个用户具有的角色,是否有足够的权限去访问某个资源 -->
<beans:bean id="myAccessDecisionManagerBean" class="com.www.common.security.DecisionManager"/>
<!-- 资源源数据定义,即定义某一资源可以被哪些角色访问 -->
<beans:bean id="securityMetadataSource" class="com.www.common.security.SecurityMetadataSource"/>
<!--session会话创建销毁-->
<beans:bean id="sessionRegistry" class="org.springframework.security.core.session.SessionRegistryImpl"/>
<!-- 登录页面 -->
<beans:bean id="loginEntryPoint" class="com.www.common.security.LoginEntryPoint">
<beans:constructor-arg name="loginFormUrl" value="/login.do"/>
</beans:bean>
<!--登录失败跳转页面,如需不使用页面返回可重写此类-->
<beans:bean id="loginFailureHandler" class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler">
<beans:property name="defaultFailureUrl" value="/login_error.do"/>
</beans:bean>
<!--登录成功跳转的页面-->
<beans:bean id="loginSuccessHandler" class="com.www.common.security.SuccessHandler">
<beans:property name="defaultTargetUrl" value="/index.do"/>
</beans:bean>
<!--被迫下线时的跳转页-->
<beans:bean id="expiredStrategy" class="org.springframework.security.web.session.SimpleRedirectSessionInformationExpiredStrategy">
<beans:constructor-arg name="invalidSessionUrl" value="/login.do" />
</beans:bean>
</beans:beans>
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/mvc 
http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
http://www.springframework.org/schema/beans 
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context 
http://www.springframework.org/schema/context/spring-context-4.0.xsd">
<!-- 配置自动扫描的包 -->
<context:component-scan base-package="com.www.controller"/>
<context:annotation-config/>
<mvc:annotation-driven/>
<!-- 对模型视图名称的解析,即在模型视图名称添加前后缀 -->
<bean id="velocityCongfig" class="org.springframework.web.servlet.view.velocity.VelocityConfigurer">
<!-- velocity配置文件路径  或者直接用velocityProperties属性 -->
<property name="configLocation" value="classpath:config/velocity.properties"/>
<!-- velocity模板路径 -->
<property name="resourceLoaderPath" value="/WEB-INF/templates/zh_jd/"/>
</bean>
<bean id="viewResolver" class="org.springframework.web.servlet.view.velocity.VelocityViewResolver">
<property name="contentType" value="text/html;charset=UTF-8"/>
<property name="suffix" value=".html"/>
<property name="exposeSpringMacroHelpers" value="true" /><!--是否使用spring对宏定义的支持-->
<property name="exposeSessionAttributes" value="true" /><!--是否开放request属性-->
<property name="requestContextAttribute" value="request"/><!--request属性引用名称-->
<property name="dateToolAttribute" value="dateTool"/>
<property name="numberToolAttribute" value="numberTool"/>
</bean>
</beans>
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://www.springframework.org/schema/data/jpa
http://www.springframework.org/schema/data/jpa/spring-jpa.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-4.3.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.3.xsd">
<aop:aspectj-autoproxy proxy-target-class="true"/>
<!-- 配置自动扫描的包 -->
<context:component-scan base-package="com.www">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
<context:exclude-filter type="annotation" expression="org.springframework.web.bind.annotation.ControllerAdvice"/>
</context:component-scan>
<!-- 配置数据源 -->
<context:property-placeholder location="classpath:config/jdbc.properties"/>
<bean id="sourceParten" class="com.alibaba.druid.pool.DruidDataSource">
<!-- 初始化连接数量 type:int -->
<property name="initialSize" value="${druid.initialSize}"/>
<!-- 最大并发数量 type:int -->
<property name="maxActive" value="${druid.maxActive}"/>
<!-- 最大空闲数量 type:int -->
<property name="maxIdle" value="10"/>
<!-- 最小空闲数量 type:int -->
<property name="minIdle" value="5"/>
<!-- 配置获取连接等待超时的时间,单位:毫秒 type:long -->
<property name="maxWait" value="10000"/>
<!-- 超过时间限制是否回收 type:boolean -->
<property name="removeAbandoned" value="true"/>
<!-- 上述回收超时时间 单位:秒 type:long -->
<property name="removeAbandonedTimeout" value="300000"/>
<!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->
<property name="timeBetweenEvictionRunsMillis" value="60000"/>
<!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->
<property name="minEvictableIdleTimeMillis" value="300000"/>
<!-- 用来检测连接是否有效的sql,要求是一个查询语句 type:sql -->
<property name="validationQuery" value="select 1"/>
<!-- 申请连接的时候检测 type:boolean -->
<property name="testWhileIdle" value="true"/>
<!-- 申请连接时执行validationQuery检测连接是否有效,配置为true会降低性能 -->
<property name="testOnBorrow" value="false"/>
<!-- 归还连接时执行validationQuery检测连接是否有效,配置为true会降低性能  -->
<property name="testOnReturn" value="false"/>
<!-- 开启PSCache,并且指定每个连接上PSCache的大小 -->
<property name="poolPreparedStatements" value="false"/>
<property name="maxPoolPreparedStatementPerConnectionSize" value="-1"/>
<!--监控统计stat日志log4j 防御SQL注入wall -->
<property name="filters" value="stat,wall"/>
</bean>
<bean id="dataSource" parent="sourceParten" init-method="init" destroy-method="close">
<property name="driverClassName" value="${jdbc.driverClassName}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<!-- 配置 JPA 的 EntityManagerFactory -->
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource"></property>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="true"/>
<property name="database" value="MYSQL"/>
</bean>
</property>
<property name="packagesToScan" value="com.www.common.pojo"></property>
<property name="jpaProperties">
<props>
<prop key="hibernate.physical_naming_strategy">
<!--hibernate4 org.hibernate.cfg.ImprovedNamingStrategy -->
<!--hibernate5 org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl-->
<!-- 驼峰转下划线 -->
com.www.common.utils.ImprovedNamingStrategy
</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
<prop key="hibernate.format_sql">true</prop>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.cache.use_second_level_cache">true</prop>
<prop key="hibernate.cache.region.factory_class">
org.hibernate.cache.ehcache.EhCacheRegionFactory
</prop>
<prop key="hibernate.cache.use_query_cache">true</prop>
</props>
</property>
<property name="sharedCacheMode" value="ENABLE_SELECTIVE"></property>
</bean>
<aop:config>
<aop:advisor pointcut="execution(* com.www.service.*.*(..))" advice-ref="txAdvice"/>
</aop:config>
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="add*" propagation="REQUIRED"/>
<tx:method name="login*" propagation="REQUIRED"/>
<tx:method name="save*" propagation="REQUIRED"/>
<tx:method name="del*" propagation="REQUIRED"/>
<tx:method name="bech*" propagation="REQUIRED"/>
<tx:method name="modify*" propagation="REQUIRED"/>
<tx:method name="update*" propagation="REQUIRED"/>
<tx:method name="*" read-only="true"/>
</tx:attributes>
</tx:advice>
<!-- 配置事务 -->
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"></property>
</bean>
<!-- 配置支持基于注解的事务 -->
<!-- <tx:annotation-driven transaction-manager="transactionManager"/> -->
<!-- 配置 SpringData -->
<jpa:repositories base-package="com.www.common.dao"/>
<!--定时任务-->
<bean id="jobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject" ref="myTask"/>
<property name="targetMethod" value="execute"/>
<!-- false表示job不会并发执行,默认为true-->
<property name="concurrent" value="false"/>
</bean>
<!--调用时间-->
<bean id="doWork" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
<property name="jobDetail" ref="jobDetail" />
<property name="cronExpression" value="0 0 0 1 * ?" />
</bean>
<!--任务调度-->
<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="triggers">
<list>
<ref bean="doWork"/>
</list>
</property>
</bean>
</beans>
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-4.2.xsd">
<!--<debug/>-->
<http pattern="/**/login.*" security="none"/>
<http pattern="/**/login_error.*" security="none"/>
<http pattern="/**/error.*" security="none"/>
<http pattern="/download/**" security="none"/>
<http pattern="/resources/**" security="none"/>
<http pattern="/upload/**" security="none"/>
<http pattern="/**/register.do" security="none"/>
<http pattern="/verify/**" security="none"/>
<global-method-security secured-annotations="enabled"/>
<http  auto-config="false" use-expressions="true" entry-point-ref="loginEntryPoint">
<!-- 禁用CSRF保护,默认是启用 -->
<csrf disabled="true"/>
<headers disabled="true"/>
<!--匿名者-->
<anonymous enabled="false"/>
<!-- 路径所需角色认证 hasRole 包含某个角色 hasAuthority包含某个权限-->
<intercept-url pattern="/admin/**" access="hasAuthority('admin_index')"/>
<intercept-url pattern="/seller/**" access="hasAuthority('seller_index')"/>
<!--<intercept-url pattern="/**" access="authenticated"/>-->
<logout logout-success-url="/login.do" logout-url="/loginout.do" delete-cookies="JSESSIONID"/>
<!--session管理-->
<custom-filter ref="concurrencyFilter" position="CONCURRENT_SESSION_FILTER"/>
<!--登录验证-->
<custom-filter ref="loginFilter" position="FORM_LOGIN_FILTER"/>
<!--权限验证-->
<custom-filter ref="myFilter" before="FILTER_SECURITY_INTERCEPTOR"/>
</http>
<beans:bean id="loginFilter" class="com.www.common.security.LoginFromFilter">
<!-- 登录提交处理 -->
<beans:property name="filterProcessesUrl" value="/shopping_login.do"/>
<!-- 登录成功跳转 -->
<beans:property name="authenticationSuccessHandler" ref="loginSuccessHandler"/>
<!-- 设置登录失败的网址 -->
<beans:property name="authenticationFailureHandler" ref="loginFailureHandler"/>
<!-- 用户拥有权限 -->
<beans:property name="authenticationManager" ref="authenticationManager"/>
<!--在线人数管理,不配置为NullAuthenticatedSessionStrategy不再进行session验证-->
<beans:property name="sessionAuthenticationStrategy" ref="sessionStrategy"/>
<!--登录页面参数-->
<beans:property name="usernameParameter" value="username"/>
<beans:property name="passwordParameter" value="password"/>
<beans:property name="codeParameter" value="code"/>
</beans:bean>
<!-- 权限认证Spring日志监听器  -->
<beans:bean class="org.springframework.security.authentication.event.LoggerListener"/>
<beans:bean class="org.springframework.security.access.event.LoggerListener"/>
<beans:bean id="myFilter" class="com.www.common.security.SecurityInterceptor">
<!--登录验证-->
<beans:property name="authenticationManager" ref="authenticationManager"/>
<!--权限验证-->
<beans:property name="accessDecisionManager" ref="myAccessDecisionManagerBean"/>
<!--访问的url资源权限信息-->
<beans:property name="securityMetadataSource" ref="securityMetadataSource"/>
</beans:bean>
<!-- 验证配置,实现用户认证的入口,主要实现UserDetailsService接口即可  -->
<authentication-manager alias="authenticationManager">
<authentication-provider ref="myAuthenticationProvider"/>
</authentication-manager>
<!--用户登录验证配置和加密方式-->
<beans:bean id="myAuthenticationProvider" class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
<beans:property name="userDetailsService" ref="myUserDetailService" />
<beans:property name="passwordEncoder" ref="passwordEncoder" />
</beans:bean>
<!--session会话总控制-->
<beans:bean id="concurrencyFilter" class="org.springframework.security.web.session.ConcurrentSessionFilter">
<beans:constructor-arg name="sessionRegistry" ref="sessionRegistry"/>
<beans:constructor-arg name="sessionInformationExpiredStrategy" ref="expiredStrategy"/>
</beans:bean>
<!--基于onAuthentication方法的代理-->
<beans:bean id="sessionStrategy" class="org.springframework.security.web.authentication.session.CompositeSessionAuthenticationStrategy">
<beans:constructor-arg>
<beans:list>
<beans:bean class="org.springframework.security.web.authentication.session.ConcurrentSessionControlAuthenticationStrategy">
<beans:constructor-arg ref="sessionRegistry"/>
<!-- 这里是配置session数量,此处为1,表示同一个用户同时只会有一个session在线 -->
<beans:property name="maximumSessions" value="1" />
<beans:property name="exceptionIfMaximumExceeded" value="false"/>
</beans:bean>
<beans:bean class="org.springframework.security.web.authentication.session.SessionFixationProtectionStrategy"/>
<beans:bean class="org.springframework.security.web.authentication.session.RegisterSessionAuthenticationStrategy">
<beans:constructor-arg ref="sessionRegistry"/>
</beans:bean>
</beans:list>
</beans:constructor-arg>
</beans:bean>
<!-- md5 -->
<beans:bean id="passwordEncoder" class="com.www.common.utils.MD5"/>
<!-- 在这个类中,读入用户的密码,角色信息,是否锁定,账号是否过期等属性信息  -->
<beans:bean id="myUserDetailService" class="com.www.common.security.MyUserDetailService"/>
<!-- 访问决策器,决定某个用户具有的角色,是否有足够的权限去访问某个资源 -->
<beans:bean id="myAccessDecisionManagerBean" class="com.www.common.security.DecisionManager"/>
<!-- 资源源数据定义,即定义某一资源可以被哪些角色访问 -->
<beans:bean id="securityMetadataSource" class="com.www.common.security.SecurityMetadataSource"/>
<!--session会话创建销毁-->
<beans:bean id="sessionRegistry" class="org.springframework.security.core.session.SessionRegistryImpl"/>
<!-- 登录页面 -->
<beans:bean id="loginEntryPoint" class="com.www.common.security.LoginEntryPoint">
<beans:constructor-arg name="loginFormUrl" value="/login.do"/>
</beans:bean>
<!--登录失败跳转页面,如需不使用页面返回可重写此类-->
<beans:bean id="loginFailureHandler" class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler">
<beans:property name="defaultFailureUrl" value="/login_error.do"/>
</beans:bean>
<!--登录成功跳转的页面-->
<beans:bean id="loginSuccessHandler" class="com.www.common.security.SuccessHandler">
<beans:property name="defaultTargetUrl" value="/index.do"/>
</beans:bean>
<!--被迫下线时的跳转页-->
<beans:bean id="expiredStrategy" class="org.springframework.security.web.session.SimpleRedirectSessionInformationExpiredStrategy">
<beans:constructor-arg name="invalidSessionUrl" value="/login.do" />
</beans:bean>
</beans:beans>
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="DEBUG" monitorInterval="1800">
<properties>
<property name="LOG_HOME">D:/logs/</property>
<property name="FILE_NAME">SSSlog</property>
</properties>
<Appenders>
<!--控制台输出-->
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{HH:mm:ss.SSS}==>>%class{36}===>>>%msg%n" />
<ThresholdFilter level="DEBUG" onMatch="ACCEPT" onMismatch="DENY"/>
</Console>
<!--临时日志,每次启动程序会清空-->
<File name="Log" fileName="${LOG_HOME}/${FILE_NAME}-tmp.log">
<PatternLayout pattern="%d{HH:mm:ss.SSS} %-5level %class{36} %L %M - %msg%xEx%n"/>
<ThresholdFilter level="DEBUG" onMatch="ACCEPT" onMismatch="DENY"/>
</File>
<!--自动存入按年份-月份建立的文件夹 info级别-->
<RollingRandomAccessFile name="InfoLog" fileName="${LOG_HOME}/${FILE_NAME}/info.log"
filePattern="${LOG_HOME}/${FILE_NAME}/info/$${date:yyyy-MM}/%d{yyyy-MM-dd}-%i.log" immediateFlush="true">
<PatternLayout pattern="%date{yyyy-MM-dd HH:mm:ss.SSS} %level [%thread][%file:%line] - %msg"/>
<ThresholdFilter level="INFO" onMatch="ACCEPT" onMismatch="DENY"/>
<Policies>
<TimeBasedTriggeringPolicy/>
<SizeBasedTriggeringPolicy size="20 MB"/>
</Policies>
<DefaultRolloverStrategy max="20"/>
</RollingRandomAccessFile>
</Appenders>
<Loggers>
<!-- 3rdparty Loggers -->
<logger name="org.springframework.core" level="INFO"/>
<logger name="org.springframework.beans" level="INFO"/>
<logger name="org.springframework.context" level="INFO"/>
<logger name="org.springframework.web" level="INFO"/>
<logger name="com.youke.action.app" level="INFO" includeLocation="true" additivity="false">
<appender-ref ref="InfoLog"/>
<appender-ref ref="Console"/>
</logger>
<logger name="com.youke.common.dao" level="Trace" includeLocation="true" additivity="false">
<appender-ref ref="InfoLog"/>
<appender-ref ref="Console"/>
</logger>
<root level="all" includeLocation="true">
<appender-ref ref="Console"/>
<appender-ref ref="InfoLog"/>
</root>
</Loggers>
</Configuration>

至此项目整合完成

完整项目下载链接https://download.csdn.net/download/qq_40615366/10589664

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/135192.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • pvzβ版下载_掌上生活app下载安装

    pvzβ版下载_掌上生活app下载安装环境要求HttpRunner是一个基于Python开发的测试框架,可以运行在macOS、Linux、Windows系统平台上。这里使用macOS系统进行演示对于python版本要求:py

  • 微信公众号网页授权40029错误「建议收藏」

    微信公众号网页授权40029错误「建议收藏」1.检查appid和secret是否正确(基本不会错,纠结了一晚上居然认为是这里错了)2.发了两次请求导致错了在url中加入”connect_redirect=1″;修改之前的url’https://api.weixin.qq.com/sns/oauth2/access_token?appid=’.$wxInfo[‘z_app_id’].’&secret=’.$wxInfo[‘z_…

  • python tkinter窗口美化_jquery进度条插件

    python tkinter窗口美化_jquery进度条插件前言在我们进行自动化测试的时候,用例往往是成百上千,执行的时间是几十分钟或者是小时级别。有时,我们在调试那么多用例的时候,不知道执行到什么程度了,而pytest-sugar插件能很好解决我们的痛点。

  • pycharm调试debug入门PDF_pycharm中debug无法单步调试

    pycharm调试debug入门PDF_pycharm中debug无法单步调试为了摈弃print的暴力调试法,在mentor的耳濡目染下,我开始了PyCharm的Debug。例程:defhelloworld():print(‘helloworld’)a=1b=2c=3foriinrange(5):print(i)a=3b=4c=5helloworld()print(‘end’)1.先设置红…

  • PR曲线 可算是明白了 precision recall曲线

    PR曲线 可算是明白了 precision recall曲线Inst#是样本序号,图中有20个样本。Class是groundtruth标签,p是positive样本(正例),n当然就是negative(负例)score是我的分类器对于该样本属于正例的可能性的打分。因为一般模型输出的不是0,1的标注,而是小数,相当于置信度。然后设置一个从高到低的阈值y,大于等于阈值y的被我正式标注为正例,小于阈值y的被我正式标注为负例。显然,我设置n个阈值…

  • UART串口流控制(Flow control)「建议收藏」

    UART串口流控制(Flow control)「建议收藏」一般在串行通讯中,我们会在一些上位机上看到RTS/CTS、DTR/DSR和XON/XOFF的选项,这是对流控制的选项,一般是应用于RS232接口的,是拿来调制解调器的数据通讯的一、流控制的作用这里讲到的“流”,指的是数据流;在数据通信中,流控制是管理两个节点之间数据传输速率的过程,以防止出现接收端的数据缓冲区已满,而发送端依然继续发送数据,所导致数据丢失二、工作原理当接收端的数…

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号