spring boot security jwt

image.png
<dependencies>
     <dependency>
            <groupId>org.json</groupId>
            <artifactId>json</artifactId>
        </dependency>
        <!-- jwt  json web token -->
        <dependency>
          <groupId>io.jsonwebtoken</groupId>
          <artifactId>jjwt</artifactId>
          <version>0.7.0</version>
        </dependency>
        <!-- spring boot security -->
         <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
            <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.2.0</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
<dependencies>
package cn.etstone.evm.configuration.security;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
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.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import cn.etstone.evm.configuration.jwt.JWTAuthenticationFilter;
import cn.etstone.evm.configuration.jwt.JWTLoginFilter;


@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true) // 允許進入頁面方法前檢驗
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    private static final Logger LOGGER = LoggerFactory.getLogger(WebSecurityConfig.class);
    
    @Autowired
    private SecurityAuthenticationProvider securityAuthenticationProvider;
    
//  @Autowired
//  private AuthSuccessHandler authSuccessHandler;//登錄成功跳轉(zhuǎn)頁面
    
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        LOGGER.debug("WebSecurityConfig.configure(HttpSecurity http)");
        http
            .exceptionHandling().accessDeniedPage("/error/403").and()
            .anonymous().and()
            .servletApi().and()
            .headers().cacheControl()
            .and().and()
            .authorizeRequests().antMatchers("/favicon.ico","/static/plugins/**","/static/css/**",
                        "/static/fonts/**","/static/login/**","/login").permitAll()
            
//          .antMatchers(HttpMethod.POST, "/login").permitAll() // 所有 /login 的POST請求 都放行
            
                .anyRequest().authenticated() //所有其他請求需要進行身份驗證
            .and()
                .formLogin() // 基于 Form
                .loginPage("/login").permitAll()// 表單登錄驗證
                .and().logout().permitAll()
                
            .and()
                // 由于使用的是JWT叶骨,我們這里不需要csrf
                .csrf().disable().sessionManagement()
                // 基于token,所以不需要session
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS);    
            // 禁用緩存
            http.headers().cacheControl();
            
            http
                // 添加一個過濾器 所有訪問 /login 的請求交給 JWTLoginFilter 來處理 這個類處理所有的JWT相關(guān)內(nèi)容
                .addFilterBefore(new JWTLoginFilter("/login", authenticationManager()),UsernamePasswordAuthenticationFilter.class)
                // 添加一個過濾器驗證其他請求的Token是否合法
                .addFilterBefore(new JWTAuthenticationFilter(),UsernamePasswordAuthenticationFilter.class);
    }
    
     // 使用自定義身份驗證組件
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        LOGGER.debug("使用自定義身份驗證組件WebSecurityConfig.configure(AuthenticationManagerBuilder auth)");
        auth.authenticationProvider(securityAuthenticationProvider);
    }

}
package cn.etstone.evm.configuration.security;

import java.util.ArrayList;
import java.util.List;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

import cn.etstone.evm.navigation.mapper.NavigationMapper;
import cn.etstone.evm.system.entity.NavigationDTO;
import cn.etstone.evm.system.entity.RoleNavigationDTO;
import cn.etstone.evm.system.entity.UserRoleNavigationInfo;
import cn.etstone.evm.system.mapper.UserRoleMapper;

@Service
public class SecurityAuthenticationProvider implements AuthenticationProvider { //自定義UserDetailsService 接口
    
    private static final Logger LOGGER = LoggerFactory.getLogger(SecurityAuthenticationProvider.class);

    @Autowired
    private UserRoleMapper userRoleMapper;
    @Autowired
    private NavigationMapper navigationMapper;
    
    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        if(authentication == null || StringUtils.isBlank(authentication.getName()) || StringUtils.isBlank((String)authentication.getCredentials())){
            return null;
        }
        
        LOGGER.debug("authentication:{}",authentication);
        
        String username = authentication.getName();
        LOGGER.debug("authentication.getName();:{}",authentication.getName());
        String password = (String) authentication.getCredentials();
        LOGGER.debug("password:{}",password);
        
        UserRoleNavigationInfo userRoleInfo = userRoleMapper.findLoginName(username);
        LOGGER.debug("userRoleInfo:{}",userRoleInfo);
        
        List<NavigationDTO> findAllNavigationDTO = navigationMapper.findAllNavigationDTO();
        LOGGER.debug("findAllNavigationDTO:{}",findAllNavigationDTO);
        
        if(userRoleInfo == null){
            LOGGER.debug("賬戶不存在userRoleInfo:{} ",userRoleInfo);
            throw new UsernameNotFoundException("賬戶不存在");
        }
        
        if(!userRoleInfo.getUserPassword().equals(password)){
            LOGGER.debug("密碼錯誤userRoleInfo:{} ",userRoleInfo);
            throw new UsernameNotFoundException("密碼錯誤");
        }
        
        if(userRoleInfo.getUserState().equalsIgnoreCase("DISABLE")){
            LOGGER.debug("用戶沒啟用userRoleInfo:{} ",userRoleInfo);
            throw new UsernameNotFoundException("用戶沒啟用");
        }
        
        List<RoleNavigationDTO> roleNavigationDTOs = userRoleInfo.getRoleNavigationDTOs();
        if(roleNavigationDTOs == null || roleNavigationDTOs.isEmpty()){
            LOGGER.debug("用戶沒權(quán)限userRoleInfo:{} ",userRoleInfo);
            throw new UsernameNotFoundException("用戶沒權(quán)限");
        }
        
        List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
        for (RoleNavigationDTO roleNavigationDTO : roleNavigationDTOs) {
            List<NavigationDTO> navigationDTOs = roleNavigationDTO.getNavigationDTOs();
            if(navigationDTOs == null || navigationDTOs.isEmpty()){
                LOGGER.debug("用戶綁定訪問權(quán)限為空userRoleInfo:{} ",userRoleInfo);
                throw new UsernameNotFoundException("用戶綁定訪問權(quán)限為空");
            }
            for (NavigationDTO navigationDTO : navigationDTOs) {
                if(navigationDTO.getNaviPId() == 0){
                    String roleName = "ROLE_" + navigationDTO.getNaviName();
                    authorities.add(new SimpleGrantedAuthority(roleName));
                }else{
                    for (NavigationDTO navigation : findAllNavigationDTO) {
                        if(navigationDTO.getNaviPId() == navigation.getNaviId()){
                            String roleName = "ROLE_" + navigation.getNaviName() + "." + navigationDTO.getNaviName();
                            authorities.add(new SimpleGrantedAuthority(roleName));
                        }
                    } 
                }
            }
            
        }
        
//      System.err.println(authorities);
        LOGGER.debug("登錄成功");
        return new UsernamePasswordAuthenticationToken(userRoleInfo.getLoginName(),userRoleInfo.getUserPassword(), authorities);
    }

    @Override
    public boolean supports(Class<?> authentication) {
        return authentication.equals(UsernamePasswordAuthenticationToken.class);
    }
    
    
}
package cn.etstone.evm.configuration.jwt;

import java.io.IOException;

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

import org.apache.commons.lang3.StringUtils;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

import cn.etstone.evm.configuration.EVMApplicationContext;
/**
 * 最先進入驗證
 * @author feng
 *
 */
public class JWTLoginFilter extends AbstractAuthenticationProcessingFilter {

    private static final Logger LOGGER = LoggerFactory.getLogger(JWTLoginFilter.class);
    
    public JWTLoginFilter(String url, AuthenticationManager authManager) {
        super(new AntPathRequestMatcher(url));
        LOGGER.debug("JWTLoginFilter.JWTLoginFilter(String url, AuthenticationManager authManager) ");
        setAuthenticationManager(authManager);
    }

    // 登錄時需要驗證時候調(diào)用
    @Override
    public Authentication attemptAuthentication(HttpServletRequest req, HttpServletResponse res)
            throws AuthenticationException, IOException, ServletException {
        LOGGER.debug("登錄時需要驗證時候調(diào)用JWTLoginFilter.attemptAuthentication(HttpServletRequest req, HttpServletResponse res)");
        String loginName = req.getParameter("username");
        String password = req.getParameter("password");
        LOGGER.debug("username:{};password:{}",loginName,password);
        if(StringUtils.isBlank(loginName) || StringUtils.isBlank(password)){
            LOGGER.warn("登錄時需要驗證時候調(diào)用:{}未獲取到登錄名或密碼",loginName,password);
            String json = JSONResult.fillResultString(401, "沒有登錄名或密碼", JSONObject.NULL);
            res.setCharacterEncoding("UTF-8");
            res.setContentType("application/json;charset=UTF-8");
            res.setStatus(HttpServletResponse.SC_OK);
            res.getOutputStream()
                    .write(json.getBytes("UTF-8"));
            return null;
        }
//      // 返回一個驗證令牌
        return getAuthenticationManager()
                .authenticate(new UsernamePasswordAuthenticationToken(loginName, password));
    }

    // 登錄驗證成功后調(diào)用
    @Override
    protected void successfulAuthentication(HttpServletRequest req, HttpServletResponse res, FilterChain chain,
            Authentication auth) throws IOException, ServletException {
        LOGGER.debug("登錄驗證成功后調(diào)用JWTLoginFilter.successfulAuthentication:{},生成token");
        TokenAuthenticationService tokenAuthenticationService = EVMApplicationContext.getApplicationContext().getBean(TokenAuthenticationService.class);
        tokenAuthenticationService.createJWT(res, auth);
    }

    // 登錄驗證失敗后調(diào)用豌骏,這里直接灌入500錯誤返回琅翻,由于同一JSON返回,HTTP就都返回200了
    @Override
    protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response,
            AuthenticationException failed) throws IOException, ServletException {
        LOGGER.debug("登錄驗證失敗后調(diào)用JWTLoginFilter.unsuccessfulAuthentication");
        String json = JSONResult.fillResultString(401, failed.getLocalizedMessage(), JSONObject.NULL);
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json;charset=UTF-8");
        response.setStatus(HttpServletResponse.SC_OK);
        response.getOutputStream()
                .write(json.getBytes("UTF-8"));
    }

}
package cn.etstone.evm.configuration.jwt;

import java.io.IOException;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.StringUtils;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.filter.GenericFilterBean;

import cn.etstone.evm.configuration.EVMApplicationContext;

/**
 * 登錄之后驗證
 * @author feng
 *
 */
public class JWTAuthenticationFilter extends GenericFilterBean {
    
    private static final Logger LOGGER = LoggerFactory.getLogger(JWTAuthenticationFilter.class);
    
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
            throws IOException, ServletException {
        LOGGER.debug("登錄后驗證令牌");
        HttpServletRequest req = (HttpServletRequest) request;
        HttpServletResponse resp = (HttpServletResponse)response;
        System.err.println("Evm-Authorization");
        String header = req.getHeader("Evm-Authorization");
        LOGGER.debug("登錄后驗證令牌TOKEN:{}",header);
        if(StringUtils.isBlank(header)){
            LOGGER.debug("登錄后驗證令牌TOKEN有誤:{}",header);
            String json = JSONResult.fillResultString(401, "令牌錯誤或失效", JSONObject.NULL);
            resp.setCharacterEncoding("UTF-8");
            resp.setContentType("application/json;charset=UTF-8");
            resp.setStatus(HttpServletResponse.SC_OK);
            resp.getOutputStream()
                    .write(json.getBytes("UTF-8"));
            resp.getOutputStream().flush();
            resp.getOutputStream().close();
            return;
        }
        
        TokenAuthenticationService tokenAuthenticationService = EVMApplicationContext.getApplicationContext().getBean(TokenAuthenticationService.class);
        Authentication authentication = tokenAuthenticationService.parseJWT(header);
        LOGGER.debug("登錄后驗證令牌TOKEN解析為:{}",authentication);
        if(authentication == null){
            LOGGER.warn("登錄后驗證令牌TOKEN錯誤或失效",authentication);
            String json = JSONResult.fillResultString(401, "令牌錯誤或失效", JSONObject.NULL);
            resp.setCharacterEncoding("UTF-8");
            resp.setContentType("application/json;charset=UTF-8");
            resp.setStatus(HttpServletResponse.SC_OK);
            resp.getOutputStream()
                    .write(json.getBytes("UTF-8"));
            resp.getOutputStream().flush();
            resp.getOutputStream().close();
            return;
        }
        
        
        SecurityContextHolder.getContext().setAuthentication(authentication);
        resp.addHeader("Evm-Authorization", header);
        LOGGER.debug("驗證令牌TOKEN成功,驗證令牌TOKEN重新返回客戶端");
        filterChain.doFilter(request, response);
    }
}
package cn.etstone.evm.configuration.jwt;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;

import javax.security.sasl.AuthenticationException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.stereotype.Service;

import cn.etstone.evm.configuration.properties.TokenPropertie;
import cn.etstone.evm.navigation.mapper.NavigationMapper;
import cn.etstone.evm.system.entity.NavigationDTO;
import cn.etstone.evm.system.entity.RoleNavigationDTO;
import cn.etstone.evm.system.entity.UserRoleNavigationInfo;
import cn.etstone.evm.system.mapper.UserRoleMapper;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;

/**
 * 添加構(gòu)造jwt及解析jwt的幫助類JwtHelper.java
 * 
 * @author feng
 *
 */
@Service
public class TokenAuthenticationService {
    
    private static final Logger LOGGER = LoggerFactory.getLogger(TokenAuthenticationService.class);

    @Autowired
    private UserRoleMapper userRoleMapper;
    @Autowired
    private NavigationMapper navigationMapper;
    @Autowired
    private TokenPropertie tokenPropertie;
    
    
    /**
     * 解析jwt 獲取登錄名
     * 
     * @param jsonWebToken
     * @return
     * @throws ServletException
     * @throws AuthenticationException
     */
    @Cacheable(value="system", keyGenerator="evmKeyGenerator")
    public  Authentication parseJWT(String jsonWebToken) {
        LOGGER.debug("解析jwt:{}",jsonWebToken);
        if (jsonWebToken == null || jsonWebToken.isEmpty()) {
            return null;
        }
        try {
            Claims claims = null;
            claims = Jwts.parser().setSigningKey(tokenPropertie.getSecret()) // 驗簽
                    .parseClaimsJws(jsonWebToken).getBody();
            if ("EVM".equals(claims.getIssuer())) {
                String loginName = claims.getAudience();
                LOGGER.debug("解析jwt成功獲取登錄名:{}",loginName);
                if(StringUtils.isBlank(loginName)){
                    LOGGER.debug("解析jwt未獲取到登錄名");
                    return null;
                }
                UserRoleNavigationInfo userRoleNavigationInfo = userRoleMapper.findLoginName(loginName);
                if(userRoleNavigationInfo == null){
                    LOGGER.debug("解析jwt未找到用戶");
                    return null;
                }
                List<NavigationDTO> findAllNavigationDTO = navigationMapper.findAllNavigationDTO();//獲取全部權(quán)限
                List<RoleNavigationDTO> roleNavigationDTOs = userRoleNavigationInfo.getRoleNavigationDTOs();
                if(roleNavigationDTOs == null || roleNavigationDTOs.isEmpty()){
                    LOGGER.debug("解析jwt未找到用戶權(quán)限");
                    return null;
                }
                
                List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
                for (RoleNavigationDTO roleNavigationDTO : roleNavigationDTOs) {
                    List<NavigationDTO> navigationDTOs = roleNavigationDTO.getNavigationDTOs();
                    if(navigationDTOs == null || navigationDTOs.isEmpty()){
                        LOGGER.debug("解析jwt未找到用戶權(quán)限");
                        return null;
                    }
                    for (NavigationDTO navigationDTO : navigationDTOs) {
                        if(navigationDTO.getNaviPId() == 0){
                            String roleName = "ROLE_" + navigationDTO.getNaviName();
                            authorities.add(new SimpleGrantedAuthority(roleName));
                        }else{
                            for (NavigationDTO navigation : findAllNavigationDTO) {
                                if(navigationDTO.getNaviPId() == navigation.getNaviId()){
                                    String roleName = "ROLE_" + navigation.getNaviName() + "." + navigationDTO.getNaviName();
                                    authorities.add(new SimpleGrantedAuthority(roleName));
                                }
                            } 
                        }
                    }
                    
                }
                LOGGER.debug("解析jwt令牌成功登錄名:{},權(quán)限:{}",loginName,authorities);
                return loginName != null ? new UsernamePasswordAuthenticationToken(loginName, null, authorities) : null;
            } else {
                LOGGER.warn("解析jwt令牌錯誤失敗");
                return null;
            }
        } catch (Exception e) {
            LOGGER.warn("解析jwt失斏硅尽:{}");
            return null;
        }
    }

    /**
     * 生成jwt
     * 
     * @param authentication
     * @return
     */
    public void createJWT(HttpServletResponse response, Authentication authentication) {
        // 權(quán)限
        /*  Collection<? extends GrantedAuthority> authorities =
          authentication.getAuthorities(); List<String> roles = new
          ArrayList<String>(); 
          for (GrantedAuthority grantedAuthority : authorities)
          { roles.add(grantedAuthority.getAuthority()); }*/
          
        // 生成JWT
        LOGGER.debug("生成jwt authentication:{}",authentication);
        String jwt = Jwts.builder().setId(UUID.randomUUID().toString()) // ID
                .setIssuer(tokenPropertie.getIssuer()) // 發(fā)布者
                .setAudience(authentication.getName()) // 用戶名
                // .claim("roles", roles) // 權(quán)限
                .setExpiration(new Date(tokenPropertie.getExpirationtime())) // 有效期設(shè)置
                .signWith(SignatureAlgorithm.HS256, tokenPropertie.getSecret()).compact(); // 簽名設(shè)置
        LOGGER.debug("生成jwt jwt成功:{}",jwt);
        try {
            response.setContentType("application/json");
            response.setStatus(HttpServletResponse.SC_OK);
            response.getOutputStream().println(JSONResult.fillResultString(0, "", jwt));
            response.getOutputStream().flush();
            response.getOutputStream().close();
        } catch (IOException e) {
            e.printStackTrace();
        }

//      return jwt;
    }
}
package cn.etstone.evm.configuration.jwt;

import org.json.JSONObject;

public class JSONResult {
    public static String fillResultString(Integer status, String message, Object result){
        JSONObject jsonObject = new JSONObject(){{
            put("status", status);
            put("message", message);
            put("result", result);
        }};
        return jsonObject.toString();
    }
}
package cn.etstone.evm.configuration;

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

@Component
public class EVMApplicationContext implements ApplicationContextAware {
    
    private static ApplicationContext applicationContext = null;

    public static ApplicationContext getApplicationContext() {
        return applicationContext;
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        EVMApplicationContext.applicationContext = applicationContext;
    }

}
package cn.etstone.evm.interceptor;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Optional;

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

import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.servlet.ModelAndView;

import com.google.gson.Gson;

import cn.etstone.evm.common.BizException;
import cn.etstone.evm.configuration.jwt.JSONResult;
import cn.etstone.evm.status.entity.Status;
import cn.etstone.evm.status.enums.BizCode;

/**
 * 異常攔截<br/>
 * 攔截所有未處理的異常
 * @author cpc
 *
 */
@RestControllerAdvice
public class ExceptionInterceptor {

    private static final Logger LOG = LoggerFactory.getLogger(ExceptionInterceptor.class);
    private static final Gson GSON = new Gson();
    
    private static final BizCode DEFAULT_CODE = BizCode.SERVER_EXCEPTION;
    
    private static final String DEFAULT_ERROR_PAGE = "/500";

    @Autowired
    private MessageSource messageSource;
    
    /**
     * 異常處理器
     */
    @ExceptionHandler(value={Exception.class})
    public ModelAndView exceptionHandler(Exception exception, WebRequest request){
        LOG.error("捕獲到未處理異常, 異常: {}, {}, {}", exception.getMessage(), request.getContextPath(), request.getDescription(true));
        if(LOG.isDebugEnabled()){
            exception.printStackTrace();
        }
        
        String messageCode = String.format("%s.%s", DEFAULT_CODE.getPrefix(), DEFAULT_CODE.getMessage());
        String message = this.messageSource.getMessage(messageCode, null, null, LocaleContextHolder.getLocale());
        ModelAndView errorView = new ModelAndView("redirect:" + DEFAULT_ERROR_PAGE);
        errorView.addObject("message", message);
        return errorView;
    }
    
    @ExceptionHandler(value={AccessDeniedException.class})
    public void accessDeniedExceptionHandler(Exception exception, WebRequest request, HttpServletResponse response) throws Exception, IOException{
        LOG.error("未授權(quán)...");
        LOG.error("捕獲到未處理異常, 異常: {}", exception.getMessage());
        if(LOG.isDebugEnabled()){
//          exception.printStackTrace();
        }
        response.setContentType("application/json;charset=UTF-8");
        String json = JSONResult.fillResultString(302, "權(quán)限不夠", JSONObject.NULL);
        response.getOutputStream()
        .write(json.getBytes("UTF-8"));
        response.flushBuffer();
    }
    
    
    /**
     * 自定義BizException異常處理器
     * @throws IOException 
     */
    @ExceptionHandler(value={BizException.class})
    public void bizExceptionHandler(Exception exception, HttpServletRequest request, HttpServletResponse response) throws IOException{
        if(LOG.isDebugEnabled()){
            exception.printStackTrace();
        }
        BizException bizException = (BizException)exception;
        int code = bizException.getCode();
        Optional<BizCode> bizCode = BizCode.of(code);
        String message = null;
        if(bizCode.isPresent()){
            String messageCode = String.format("%s.%s", bizCode.get().getPrefix(), bizCode.get().getMessage());
            message = this.messageSource.getMessage(messageCode, null, null, LocaleContextHolder.getLocale());
        }
        
        if(message == null){
            LOG.error("自定義BizException異常處理器: 未找到異常信息中的BizCode信息. 使用默認BizCode: {}", DEFAULT_CODE);
            String messageCode = String.format("%s.%s", DEFAULT_CODE.getPrefix(), DEFAULT_CODE.getMessage());
            message = this.messageSource.getMessage(messageCode, null, null, LocaleContextHolder.getLocale());
            if(message == null){
                LOG.error("自定義BizException異常處理器: 未找到默認BizCode信息. 默認BizCode: {}", DEFAULT_CODE);
                message = "";
            }
        }
        
        Status<Object> status = new Status<Object>(HttpStatus.OK, code, message, null);
        LOG.debug("自定義BizException異常處理器: {}", status);
        response.setContentType("application/json;charset=UTF-8");
        response.getWriter().println(GSON.toJson(status));
        response.flushBuffer();
    }
}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末嫂伞,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子拯钻,更是在濱河造成了極大的恐慌帖努,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,907評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件粪般,死亡現(xiàn)場離奇詭異拼余,居然都是意外死亡,警方通過查閱死者的電腦和手機亩歹,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,987評論 3 395
  • 文/潘曉璐 我一進店門匙监,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人小作,你說我怎么就攤上這事亭姥。” “怎么了顾稀?”我有些...
    開封第一講書人閱讀 164,298評論 0 354
  • 文/不壞的土叔 我叫張陵达罗,是天一觀的道長。 經(jīng)常有香客問我静秆,道長粮揉,這世上最難降的妖魔是什么绍载? 我笑而不...
    開封第一講書人閱讀 58,586評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮滔蝉,結(jié)果婚禮上击儡,老公的妹妹穿的比我還像新娘。我一直安慰自己蝠引,他們只是感情好阳谍,可當(dāng)我...
    茶點故事閱讀 67,633評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著螃概,像睡著了一般矫夯。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上吊洼,一...
    開封第一講書人閱讀 51,488評論 1 302
  • 那天训貌,我揣著相機與錄音,去河邊找鬼冒窍。 笑死递沪,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的综液。 我是一名探鬼主播款慨,決...
    沈念sama閱讀 40,275評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼谬莹!你這毒婦竟也來了檩奠?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,176評論 0 276
  • 序言:老撾萬榮一對情侶失蹤附帽,失蹤者是張志新(化名)和其女友劉穎埠戳,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蕉扮,經(jīng)...
    沈念sama閱讀 45,619評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡整胃,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,819評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了慢显。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片爪模。...
    茶點故事閱讀 39,932評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖荚藻,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情洁段,我是刑警寧澤应狱,帶...
    沈念sama閱讀 35,655評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站祠丝,受9級特大地震影響疾呻,放射性物質(zhì)發(fā)生泄漏除嘹。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,265評論 3 329
  • 文/蒙蒙 一岸蜗、第九天 我趴在偏房一處隱蔽的房頂上張望尉咕。 院中可真熱鬧,春花似錦璃岳、人聲如沸年缎。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,871評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽单芜。三九已至,卻和暖如春犁柜,著一層夾襖步出監(jiān)牢的瞬間洲鸠,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,994評論 1 269
  • 我被黑心中介騙來泰國打工馋缅, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留扒腕,地道東北人。 一個月前我還...
    沈念sama閱讀 48,095評論 3 370
  • 正文 我出身青樓萤悴,卻偏偏與公主長得像袜匿,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子稚疹,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,884評論 2 354

推薦閱讀更多精彩內(nèi)容