spring cloud oauth2(四) 资源服务搭建
依赖
和server依赖一样
SecurityConfig配置
package com.Lonni.resource.config;
import org.springframework.context.annotation.Configuration;
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.WebSecurityConfigurerAdapter;
@Configuration
//开启权限注解
@EnableGlobalMethodSecurity(securedEnabled = true,prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.anyRequest().permitAll();
}
}
ResourceServerConfigurerAdapter 配置
package com.Lonni.resource.config;
import cn.hutool.core.util.ArrayUtil;
import com.Lonni.resource.exception.Auth2ResponseExceptionTranslator;
import com.Lonni.resource.model.IgnorenPath;
import org.apache.commons.lang.ArrayUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.access.AccessDeniedHandler;
import java.util.Arrays;
/**
* @program: Lonni-plus
* @description: 配置资源服务(主要配置类) 继承自 ResourceServerConfigurerAdapter
* @author: lonni
* @create: 2020-11-19 21:22
*/
@Configuration
@EnableResourceServer
public class ResourceServiceConfig extends ResourceServerConfigurerAdapter {
/**
* 1:注入token存储器 tokenconfig中
*/
@Autowired
@Qualifier("jwtTokenStore")
private TokenStore tokenStore;
/**
* 2: 注入token解密器 tokenconfig中
*/
@Autowired
@Qualifier("jwtAccessTokenConverter")
private JwtAccessTokenConverter tokenConverter;
//@Autowired
// IgnorenPath ignorenPath;
@Autowired
AccessDeniedHandler accessDeniedHandler;
/**
* 配置token解析和资源id
* @param resources
* @throws Exception
*/
@Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
//这里的资源id从配置文件中读取
resources .resourceId(ignorenPath.getId())
//配置token存储
.tokenStore(tokenStore)
//是否吧token记录在session中
.stateless(true);
// 定义异常转换类生效
AuthenticationEntryPoint authenticationEntryPoint = new OAuth2AuthenticationEntryPoint();
((OAuth2AuthenticationEntryPoint) authenticationEntryPoint)
.setExceptionTranslator(new Auth2ResponseExceptionTranslator());
resources.authenticationEntryPoint(authenticationEntryPoint)
.accessDeniedHandler(accessDeniedHandler);
}
/**
* 配置资源服务需要拦截的请求 可以在这里增加白名单配置
* @param http
* @throws Exception
*/
@Override
public void configure(HttpSecurity http) throws Exception {
String[] allIgnoredPath = ignorenPath.getAllIgnoredPath();
http.authorizeRequests().
//设置白名单 其他全部都需要权限访问
// antMatchers(allIgnoredPath)
.permitAll()
.anyRequest().authenticated();
}
}
异常捕获类
AccessDeniedHandler 授权拒绝错误处理类
package com.Lonni.resource.exception;
import com.Lonni.common.viewmodels.AjaxResult;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.extension.api.R;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.SneakyThrows;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.oauth2.provider.error.OAuth2AccessDeniedHandler;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
/**
* @descriptions:
* @author: Lonni
* @date: 2021/1/24 15:53
* @version: 1.0
*/
@Component
public class AccessDeniedHandler extends OAuth2AccessDeniedHandler {
/**
* 授权拒绝处理
*/
@Override
@SneakyThrows
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException authException) {
response.setCharacterEncoding("UTF-8");
response.setContentType("application/json; charset=utf-8");
AjaxResult result= AjaxResult.FAIL("权限错误");
response.setStatus(HttpStatus.UNAUTHORIZED.value());
PrintWriter printWriter = response.getWriter();
printWriter.append(JSON.toJSONString(result));
}
}
资源认证异常处理 Auth2ResponseExceptionTranslator
package com.Lonni.resource.exception;
import com.Lonni.common.viewmodels.AjaxResult;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.InsufficientAuthenticationException;
import org.springframework.security.oauth2.client.resource.OAuth2AccessDeniedException;
import org.springframework.security.oauth2.common.exceptions.InvalidTokenException;
import org.springframework.security.oauth2.common.exceptions.OAuth2Exception;
import org.springframework.security.oauth2.provider.error.WebResponseExceptionTranslator;
/**
* 资源认证异常处理
*/
public class Auth2ResponseExceptionTranslator implements WebResponseExceptionTranslator {
@Override
public ResponseEntity<OAuth2Exception> translate(Exception throwable) throws Exception {
throwable.printStackTrace();
String message=throwable.getMessage();
if (throwable instanceof InvalidTokenException) {
if (message.contains("Access token expired")){
return new ResponseEntity(
AjaxResult.FAIL("token已过期") , HttpStatus.FORBIDDEN);
}
return new ResponseEntity(
AjaxResult.FAIL("token不正确") , HttpStatus.FORBIDDEN);
}
if (throwable instanceof OAuth2AccessDeniedException) {
String resourceid=message.substring(message.lastIndexOf("(")+1,message.lastIndexOf(")"));
return new ResponseEntity(
AjaxResult.FAIL("您没有资源:["+resourceid+"]访问的权限!") , HttpStatus.FORBIDDEN);
}
if (throwable instanceof InsufficientAuthenticationException){
System.out.println("is InsufficientAuthenticationException");
return new ResponseEntity(
AjaxResult.FAIL("身份票据不合法,请登录!") , HttpStatus.FORBIDDEN);
}
return new ResponseEntity(AjaxResult.FAIL("权限错误"), HttpStatus.FORBIDDEN);
}
}
ControllerAdvice处理
package com.Lonni.resource.exception;
import com.Lonni.common.viewmodels.AjaxResult;
import com.Lonni.core.utils.PrintStatckUtil;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.authentication.InsufficientAuthenticationException;
import org.springframework.security.oauth2.client.resource.OAuth2AccessDeniedException;
import org.springframework.security.oauth2.common.exceptions.InvalidTokenException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
/**
* @author lonni
* @Description: TODO
* @date 2020/11/1917:49
*/
@ControllerAdvice
public class ResourceAdviceHandle {
@ExceptionHandler(value = AccessDeniedException.class)
@ResponseBody
public AjaxResult AccessDeniedException(AccessDeniedException ex) {
PrintStatckUtil.consolePrintIsDebug(ex);
return AjaxResult.FAIL("权限不足,"+ex.getMessage());
}
@ExceptionHandler(value = InvalidTokenException.class)
@ResponseBody
public AjaxResult invalidTokenException(InvalidTokenException ex) {
PrintStatckUtil.consolePrintIsDebug(ex);
return AjaxResult.FAIL("token不正确");
}
@ExceptionHandler(value ={ InsufficientAuthenticationException.class, OAuth2AccessDeniedException.class})
@ResponseBody
public AjaxResult insufficientAuthenticationException(Exception ex) {
PrintStatckUtil.consolePrintIsDebug(ex);
String message = ex.getMessage();
if (message.contains("Access token expired")){
return AjaxResult.FAIL("token已失效");
}
if (message.contains("resource id")){
String resourceid=message.substring(message.lastIndexOf("("),message.lastIndexOf(")"));
return AjaxResult.FAIL("您没有资源:["+resourceid+"]的访问权限!");
}
return AjaxResult.FAIL(message);
}
}