我是用spring security,oauth2 ,zuul,springcloud做路由,同时进行api接口授权管理。springsecurity 坐在路由层,在ResourceServerConfigurerAdapter 类中 把accessDecisionManger()决策,authenticationManager,securityMetadataSource()通过FilterSecurityInterceptor加进来,在配置文件中进行auther2权限认证服务器的配置。
先贴出pom.xml
启动类
package com;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
/** 服务网管
* @author wf
* @Time 2019年1月17日 15:19
* @version 1.0
*/
@SpringBootApplication
@EnableEurekaClient
@EnableZuulProxy
@MapperScan("com.neusoft.dao")
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
oauth2的资源代码
package com.neusoft.config;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
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.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.web.access.intercept.FilterSecurityInterceptor;
import org.springframework.web.cors.CorsConfiguration;
/**
* @Description: 配置资源服务器(oauth2)
* @author: wf
* @Date: 2018-11-26
* @Time: 15:08
*/
@Configuration
@EnableResourceServer
@EnableGlobalMethodSecurity(securedEnabled = true)
public class ResourceServiceConfig extends ResourceServerConfigurerAdapter {
private AuthenticationManager authenticationManager;
private authorityService authorityService;
@Bean//应用启动时加载权限信息
public FilterInvocationSecurityMetadataSource securityMetadataSource(){
return new SecurityMetadataSourceImpl(authorityService);
}
@Bean//配置授权管理器
public AccessDecisionManager accessDecisionManager(){
return new AccessDecisionManagerImpl():
}
//获取被拦截的url所需的全部权限,通过AccessDecisionManager决定用户是否访问该url
@Bean
public FilterSecurityInterceptor filterSecurityInterceptor(){
FilterSecurityInterceptor filterSecurityInterceptor=new FilterSecurityInterceptor();
filterSecurityInterceptor.setSecurityMetadataSource(securityMetadataSource());
filterSecurityInterceptor.setAuthenticationManager(authenticationManager);
filterSecurityInterceptor.setAccessDecisionManager(accessDecisionManager());
}
@Override
public void configure(HttpSecurity http) throws Exception {
http .csrf().disable()
.authorizeRequests()
.antMatchers("/**")
.authenticated()
.antMatchers("actuator/*").permitAll()//定义这两个链接不需要登录可访问
.and()
.exceptionHandling()
.authenticationEntryPoint((request, response, authException) -> response.sendError(HttpServletResponse.SC_UNAUTHORIZED))
/* .permitAll()*/
//跨域配置
.and().cors().configurationSource(request -> {
CorsConfiguration corsConfiguration = new CorsConfiguration();
corsConfiguration.addAllowedHeader("*");
corsConfiguration.addAllowedOrigin(request.getHeader("Origin"));
corsConfiguration.addAllowedMethod("*");
corsConfiguration.setAllowCredentials(true);
corsConfiguration.setMaxAge(3600L);
return corsConfiguration;
});
//自定义过滤器
//把springsecurity决策管理那套东西通过过滤器加进来
/* http.addFilterAt(myFilterSecurityInterceptor, FilterSecurityInterceptor.class); */
}
@Override
public void configure(ResourceServerSecurityConfigurer resources)
throws Exception {
super.configure(resources);
}
}
配置apppliction.yml
spring:
profiles:
#包含的配置项
include:
- single-datasource
# - quartz
#启用配置项级别
active: prod
---
spring:
application:
name: service-zuul
redis:
host: localhost
port: 6379
server:
port: 8082
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8080/eureka/
mybatis:
mapper-locations: classpath*:**/mappers/*.xml
type-aliases-package: com.neusoft.entity
configuration:
map-underscore-to-camel-case: true
use-generated-keys: true
use-column-label: true
cache-enabled: true
call-setters-on-nulls: true
logging:
level:
root: error
org:
springframework: info
security:
oauth2:
authorization:
check-token-access: http://127.0.0.1:8081/oauth/check_token
resource:
user-info-uri: http://127.0.0.1:8081/user/me
id: oa
###路由
zuul:
routes:
api-a: #id
path: /api-a/** #路径
serviceId: EURKA-CLIENT1 #子服务id
api-b:
path: /api-b/**
serviceId: EURKA-CLIENT131/
最后就是加入springsecurity 决策器的三大件,决策器,资源管理,用户管理(因为认证是通过认证服务器来,固此出去去掉),拦截器
决策器:
import java.util.Collection;
import java.util.Iterator;
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 org.springframework.stereotype.Service;
/**决策器
* @author 王峰
* @Time:2019年1月18日 下午4:37:30
* @version 1.0
*/
@Service
public class MyAccessDecisionManager implements AccessDecisionManager {
// decide 方法是判定是否拥有权限的决策方法,
//authentication 是释CustomUserService中循环添加到 GrantedAuthority 对象中的权限信息集合.
//object 包含客户端发起的请求的requset信息,可转换为 HttpServletRequest request = ((FilterInvocation) object).getHttpRequest();
//configAttributes 为MyInvocationSecurityMetadataSource的getAttributes(Object object)这个方法返回的结果,此方法是为了判定用户请求的url 是否在权限表中,如果在权限表中,则返回给 decide 方法,用来判定用户是否有此权限。如果不在权限表中则放行。
@Override
public void decide(Authentication authentication, Object object, Collection
if(null== configAttributes || configAttributes.size() <=0) {
return;
}
ConfigAttribute c;
String needRole;
for(Iterator
c = iter.next();
needRole = c.getAttribute();
for(GrantedAuthority ga : authentication.getAuthorities()) {//authentication 为在注释1 中循环添加到 GrantedAuthority 对象中的权限信息集合
if(needRole!=null&&needRole.trim().equals(ga.getAuthority())) {
return;
}
}
}
throw new AccessDeniedException("无权访问,请联系管理员");
}
@Override
public boolean supports(ConfigAttribute attribute) {
return true;
}
@Override
public boolean supports(Class> clazz) {
return true;
}
}
资源管理器
package com.neusoft.config;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServletHttpHandlerAdapter;
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 org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.stereotype.Service;
import com.neusoft.center_common.utils.LogUtil;
import com.neusoft.entity.Resouces;
import com.neusoft.entity.Role;
import com.neusoft.servers.ResouceService;
import com.neusoft.servers.RoleService;
/**资源管理
* @author 王
* @Time:2019年1月18日 下午4:38:36
* @version 1.0
*/
@Service
public class MyInvocationSecurityMetadataSourceService implements
FilterInvocationSecurityMetadataSource {
@Autowired
private RoleService roleService;
@Autowired
private ResouceService resouceService;
private HashMap
/**
* 加载权限表中所有权限
*/
public void loadResourceDefine(){
try {
ma = new HashMap
List
for (Resouces re : resources) {
Collection
ConfigAttribute ca = null;
List
if (roles == null) {
} else {
for (Role r : roles) {
ca = new SecurityConfig(r.getAuth_role_id());
cc.add(ca);
}
ma.put(re.getAuth_res_url(), cc);
}
}
} catch (Exception e) {
LogUtil.doErr("资源管理中查询全部资源", e);
}
}
//此方法是为了判定用户请求的url 是否在权限表中,如果在权限表中,则返回给 decide 方法,用来判定用户是否有此权限。如果不在权限表中则放行。
@Override
public Collection
if(ma ==null) loadResourceDefine();
//object 中包含用户请求的request 信息
String url= ((FilterInvocation) object).getRequestUrl();
AntPathRequestMatcher matcher;
String resUrl;
for(Iterator
resUrl = iter.next();
if(url.contains(resUrl)) {
return ma.get(resUrl);
}
}
return null;
}
@Override
public Collection
return null;
}
@Override
public boolean supports(Class> clazz) {
return true;
}
}