Spring开发中的异常处理

来源:互联网 发布:监控数据恢复软件 编辑:程序博客网 时间:2024/05/16 02:38

1.经常会出现@Autowired注入失败,说什么依赖找不到,原因之一是注入依赖对象存在错误,另外一个就是依赖对象确实是不存在

例如看到官网直接注入RestTemplate,如下

@Autowired

 private RestTemplate restTemplate;

按照这个写法,我嫩是注入不成功,http://stackoverflow.com/questions/36151421/could-not-autowire-fieldresttemplate-in-spring-boot-application

解决方法一种是添加下面的代码,我在application中加的

 @Bean
 public RestTemplate restTemplate() {
        return new RestTemplate();
  }

2.spring boot使用redis存储spring session

.maximumSessions(1).maxSessionsPreventsLogin(false).invalidSessionStrategy(new SimpleInvalidSessionStrategy())

在一个浏览器登录成功以后,在另一个浏览器登录会把第一个浏览器登录的session覆盖掉,在第一个浏览器接着点击链接地址却发现并没有进入SimpleInvalidSessionStrategy,仍然校验通过,问题目前还没有解决。

网上的说法是当使用SessionManagementConfigurer的maximumSession(int)时不用忘记为应用配置HttpSessionEventPublisher,这样能保证过期的session能够被清除。发现session确实被清理掉了,但是查看ConcurrentSessionFilter类的源代码doFilter函数在没有session的时候并没有做限制判断,浏览器再次请求的时候有session==null和info==null两种情况

public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {    HttpServletRequest request = (HttpServletRequest)req;    HttpServletResponse response = (HttpServletResponse)res;    HttpSession session = request.getSession(false);    if(session != null) {        SessionInformation info = this.sessionRegistry.getSessionInformation(session.getId());        if(info != null) {            if(info.isExpired()) {                this.doLogout(request, response);                String targetUrl = this.determineExpiredUrl(request, info);                if(targetUrl != null) {                    this.redirectStrategy.sendRedirect(request, response, targetUrl);                    return;                }                response.getWriter().print("This session has been expired (possibly due to multiple concurrent logins being attempted as the same user).");                response.flushBuffer();                return;            }            this.sessionRegistry.refreshLastRequest(info.getSessionId());        }    }    chain.doFilter(request, response);}

暂时找不到配置文件哪里有问题,两种临时解决方案

1).拦截器拦截所有的web请求检测是否有登录信息,没有则拒绝

2).在AbstractSecurityInterceptor的doFilter中过滤

在自定义AbstractSecurityInterceptor类的doFilter判断在下面三种情况下拒绝请求

a.session不存在; b:session存在sessionInformation不存在;c:访问路径需要session校验,如获取校验码不需要session校验,/error系统自带的异常处理路径不需要拒绝

自定义SessionRegistryImpl,在新建session时根据用户名把同用户名的session删除这样被挤掉的用户就不需要二次请求才提示session过期,这种方案暂时发现了问题

下面是方案一的实现代码

HttpSessionInterceptora.java

import lombok.extern.slf4j.Slf4j;import org.apache.commons.lang3.StringUtils;import org.springframework.stereotype.Component;import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import javax.servlet.http.HttpSession;import java.io.IOException;import java.io.PrintWriter;@Slf4j@Componentpublic class HttpSessionInterceptor extends HandlerInterceptorAdapter {    @Override    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {        String method = request.getMethod();        boolean flag = false;        if(!StringUtils.equalsIgnoreCase(method,"GET")&&StringUtils.equalsIgnoreCase(method,"POST")                &&StringUtils.equalsIgnoreCase(method,"PUT")                &&StringUtils.equalsIgnoreCase(method,"DELETE")){            return true;        }        flag = checkHttpSession(response, request);        return flag;    }    private boolean checkHttpSession(HttpServletResponse response, HttpServletRequest request) throws IOException, HCBusinessException {        HttpSession session = request.getSession(false);        if (session==null||session.getAttribute("SPRING_SECURITY_CONTEXT") == null) {            response.setCharacterEncoding("UTF-8");            response.setContentType("application/json; charset=utf-8");            response.setStatus(HttpServletResponse.SC_FORBIDDEN);            PrintWriter out;            out = response.getWriter();            out.append("{\"success\":false,\"value\":null,\"message\":\"unauthorized\"}");            out.close();        }        return Boolean.TRUE;    }}
WebAppConfig.java
import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.web.servlet.config.annotation.InterceptorRegistry;import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;@Configurationpublic class WebAppConfig extends WebMvcConfigurerAdapter {    @Bean    public HttpSessionInterceptor httpSessionInterceptor(){        return new HttpSessionInterceptor();    }    @Override    public void addInterceptors(InterceptorRegistry registry) {        registry.addInterceptor(httpSessionInterceptor()).excludePathPatterns("/login","/logout","/getcode","/checkCode");        super.addInterceptors(registry);    }}


下面列出方案二的实现代码

MyFilterSecurityInterceptor.java

import lombok.extern.slf4j.Slf4j;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.boot.autoconfigure.security.SecurityProperties;import org.springframework.context.annotation.Configuration;import org.springframework.core.annotation.Order;import org.springframework.security.access.SecurityMetadataSource;import org.springframework.security.access.intercept.AbstractSecurityInterceptor;import org.springframework.security.access.intercept.InterceptorStatusToken;import org.springframework.security.core.session.SessionInformation;import org.springframework.security.core.session.SessionRegistry;import org.springframework.security.web.FilterInvocation;import javax.servlet.*;import javax.servlet.http.HttpServletResponse;import java.io.IOException;import java.io.PrintWriter;@Slf4j@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)public class MyFilterSecurityInterceptor extends AbstractSecurityInterceptorimplements Filter {private SecurityMetadataSource securityMetadataSource;@Autowiredprivate SessionRegistry sessionRegistryBean;public void setSecurityMetadataSource(SecurityMetadataSource securityMetadataSource) {this.securityMetadataSource = securityMetadataSource;}@Overridepublic Class<? extends Object> getSecureObjectClass() {//beforeInvocation需要判断它是否属于FilterInvocation类型return FilterInvocation.class;}@Overridepublic SecurityMetadataSource obtainSecurityMetadataSource() {return this.securityMetadataSource;}@Overridepublic void doFilter(ServletRequest request, ServletResponse response,                         FilterChain chain) throws IOException, ServletException {log.debug("------------MyFilterSecurityInterceptor.doFilter()-----------开始了....");FilterInvocation fi = new FilterInvocation(request, response, chain);invoke(fi);}public void invoke(FilterInvocation fi) throws IOException, ServletException {InterceptorStatusToken token = super.beforeInvocation(fi);try{String requestUrl=fi.getRequestUrl();if((fi.getRequest().getSession(false)!=null&&sessionRegistryBean.getSessionInformation(fi.getRequest().getSession(false).getId())!=null)||requestUrl.startsWith("/getcode")||requestUrl.startsWith("/checkCode")||requestUrl.startsWith("/error")){fi.getChain().doFilter(fi.getRequest(), fi.getResponse());}else{HttpServletResponse httpServletResponse=fi.getResponse();httpServletResponse.setCharacterEncoding("UTF-8");httpServletResponse.setContentType("application/json; charset=utf-8");httpServletResponse.setStatus(HttpServletResponse.SC_FORBIDDEN);PrintWriter out;out = httpServletResponse.getWriter();out.append("{\"success\":false,\"value\":null,\"message\":\"unauthorized\"}");out.close();}}finally{super.afterInvocation(token, null);}log.debug("-----------MyFilterSecurityInterceptor.doFilter()-----------拦截器该方法结束了....");}@Overridepublic void init(FilterConfig filterConfig) throws ServletException {}@Overridepublic void destroy() {}}
MySessionRegistryImpl.java

import org.MyUser;//自己的UserDetail信息存储类import org.springframework.security.core.session.SessionRegistryImpl;import org.springframework.security.core.userdetails.UserDetails;public class MySessionRegistryImpl extends SessionRegistryImpl {    public MySessionRegistryImpl() {    }    public void expireUserSessions(UserDetails newPrincipal) {        if (newPrincipal instanceof MyUser) {            int userKeyId = ((MyUser) newPrincipal).getUserKeyId();            getAllPrincipals().stream()                    .filter(principal ->                            (principal instanceof MyUser) && (userKeyId == ((MyUser) principal).getUserKeyId()))                    .forEach(principal ->                            getAllSessions(principal, true).stream()                                    .forEach(information ->//information.expireNow())                                            removeSessionInformation(information.getSessionId())                    );        }    }    @Override    public void registerNewSession(String sessionId, Object principal) {        expireUserSessions((UserDetails) principal);        super.registerNewSession(sessionId, principal);    }}
使用代码片段

import org.springframework.beans.factory.annotation.Autowired;import org.springframework.boot.autoconfigure.security.SecurityProperties;import org.springframework.boot.web.servlet.ServletListenerRegistrationBean;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.core.annotation.Order;import org.springframework.core.env.Environment;import org.springframework.security.authentication.AuthenticationManager;import org.springframework.security.authentication.dao.DaoAuthenticationProvider;import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;import org.springframework.security.config.annotation.web.builders.HttpSecurity;import org.springframework.security.config.annotation.web.builders.WebSecurity;import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;import org.springframework.security.config.http.SessionCreationPolicy;import org.springframework.security.core.session.SessionRegistry;import org.springframework.security.core.session.SessionRegistryImpl;import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;import org.springframework.security.crypto.password.PasswordEncoder;import org.springframework.security.web.AuthenticationEntryPoint;import org.springframework.security.web.access.AccessDeniedHandler;import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;import org.springframework.security.web.authentication.AuthenticationFailureHandler;import org.springframework.security.web.authentication.AuthenticationSuccessHandler;import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;import org.springframework.security.web.session.HttpSessionEventPublisher;public abstract class AbstractSecurityConfig extends WebSecurityConfigurerAdapter {    ...    @Autowired    private SessionRegistry sessionRegistryBean;   @Override    protected void configure(HttpSecurity http) throws Exception {        ...        //session管理        http.sessionManagement().sessionFixation().newSession().maximumSessions(1).maxSessionsPreventsLogin(false).expiredUrl("/login").sessionRegistry(sessionRegistryBean)        .and().invalidSessionStrategy(new SimpleInvalidSessionStrategy());    }    //显式声明SessionRegistry,解决maxSessionPreventsLogin无效的问题    @Bean    public SessionRegistry sessionRegistryBean(){        return new MySessionRegistryImpl();    }    ...}



0 0
原创粉丝点击