权限-Spring Security实现分布式系统授权(九)
步骤
1、UAA认证服务负责认证授权。
2、所有请求经过 网关到达微服务
3、网关负责鉴权客户端以及请求转发
4、网关将token解析后传给微服务,微服务进行授权。
Eureka注册中心
新建eureka子模块
pom.xml
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
</dependencies>
application.yml
##单节点eureka
server:
port: 7000 #指定运行端口
#eureka配置
eureka:
instance:
hostname: localhost #指定主机地址 表示eureka服务端的实例名称
client:
register-with-eureka: false #指定是否要注册到注册中心(默认true) false表示eureka服务不注册自己
fetch-registry: false #指定是否要从注册中心获取服务(默认true)false就表明自己是注册中心,不需要注册
service-url: #将默认的服务地址改为自己的地址
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
启动类
package org.dong.oauth.eureka;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@SpringBootApplication
@EnableEurekaServer
public class EurekaApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaApplication.class, args);
}
}
修改uaa和order
uaa和order都需要添加的依赖如下
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
uaa和order都需要在application.yml中配置eureka,将自己注册到eureka
eureka:
client:
service-url:
defaultZone: http://localhost:7000/eureka/
然后分别在他们的主启动类上加上@EnableEurekaClient这个注解表明自己是eureka的客服端
最后启动eureka,uaa和order。访问http://localhost:7000/,我们发现uaa和order就被注册到eureka中了。
搭建网关
网关整合 OAuth2.0 有两种思路,一种是认证服务器生成jwt令牌, 所有请求统一在网关层验证,判断权限等操作; 另一种是由各资源服务处理,网关只做请求转发。
我们选用第一种。我们把API网关作为OAuth2.0的资源服务器角色,实现接入客户端权限拦截、令牌解析并转发当
前登录用户信息(jsonToken)给微服务,这样下游微服务就不需要关心令牌格式解析以及OAuth2.0相关机制了。
API网关在认证授权体系里主要负责两件事:
(1)作为OAuth2.0的资源服务器角色,实现接入方权限拦截。
(2)令牌解析并转发当前登录用户信息(明文token)给微服务
微服务拿到明文token(明文token中包含登录用户的身份和权限信息)后也需要做两件事:
(1)用户授权拦截(看当前用户是否有权访问该资源)
(2)将用户信息存储进当前线程上下文(有利于后续业务逻辑随时获取当前用户信息)
新建getway子模块作为网关模块
pom.xml
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
<!--导入zuul依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zuul</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!--Hystrix依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
<!--Ribbon-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-ribbon</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-oauth2</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-jwt</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.75</version>
</dependency>
</dependencies>
application.yml
server:
port: 9003
spring:
application:
name: gateway-server
main:
allow-bean-definition-overriding: true
cloud:
client:
ipAddress: 127.0.0.1
zuul:
retryable: true
ignored-services: "*"
add-host-header: true
sensitive-headers: "*"
routes:
uaa-service:
stripPrefix: false
path: /uaa/**
order-service:
stripPrefix: false
path: /order/**
eureka:
client:
service-url:
defaultZone: http://localhost:7000/eureka/
ribbon:
ReadTimeout: 5000
ConnectTimeout: 5000
management:
endpoints:
web:
exposure:
include: refresh,health,info,env
启动类
package org.dong.oauth.getway;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
@SpringBootApplication
@EnableZuulProxy
@EnableDiscoveryClient
public class GetWayService {
public static void main(String[] args) {
SpringApplication.run(GetWayService.class);
}
}
其实网关也可以看作一个特殊的资源服务,相关配置如下
还是使用JWT的方式存储令牌
package org.dong.oauth.getway.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;
@Configuration
public class TokenConfig {
//定义JWT令牌服务
@Autowired
private JwtAccessTokenConverter accessTokenConverter;
//密钥
private String SIGNING_KEY = "uaa123";
/**
* 存储令牌的三种方式
* 1. JdbcTokenStore(jdbc方式)
* 2. JWTTokenStore(JWT方式)
* 3. InMemoryTokenStore(内存方式,下面我们使用内存方式存储普通令牌)
*
* @return
*/
@Bean
public TokenStore tokenStore() {
return new JwtTokenStore(accessTokenConverter());
}
@Bean
public JwtAccessTokenConverter accessTokenConverter() {
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
//对称秘钥,资源服务器使用该秘钥来验证
converter.setSigningKey(SIGNING_KEY);
return converter;
}
}
网关下面有一系列的微服务,都需要在网关进行相关配置(如uaa授权服务和order资源服务)
package org.dong.oauth.getway.config;
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.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
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.token.TokenStore;
@Configuration
//表明是资源服务
@EnableResourceServer
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class ResourceServerConfig {
/**
* 1. 资源id需要和uaa模块中AuthorizationServer配置的资源id一致
* .resourceIds("res1")//客服端可以访问的资源id
*/
public static final String RESOURCE_ID = "res1";
/*** 统一认证服务(UAA) 资源拦截 */
@Configuration
@EnableResourceServer
public class UAAServerConfig extends ResourceServerConfigurerAdapter {
@Autowired
private TokenStore tokenStore;
@Override
public void configure(ResourceServerSecurityConfigurer resources) {
resources
.tokenStore(tokenStore)
.resourceId(RESOURCE_ID)
.stateless(true);
}
@Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/uaa/**")
.permitAll();
}
}
/*** 订单服务 order */
@Configuration
@EnableResourceServer
public class OrderServerConfig extends ResourceServerConfigurerAdapter {
@Autowired
private TokenStore tokenStore;
@Override
public void configure(ResourceServerSecurityConfigurer resources) {
resources
.tokenStore(tokenStore)
.resourceId(RESOURCE_ID)
.stateless(true);
}
@Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/order/**")
.access("#oauth2.hasScope('ROLE_ADMIN')");
}
}
}
因为网关类似资源服务,所以也需要配置安全服务,所有的访问都需要经过网关,我们让其放行就可以了。
package org.dong.oauth.getway.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/**")
.permitAll()
.and()
.csrf()
.disable();
}
}
网关需要解析token,然后将token转发给微服务。
package org.dong.oauth.getway.filter;
import com.alibaba.fastjson.JSON;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import org.dong.oauth.getway.common.EncryptUtil;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.OAuth2Request;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* token传递拦截
*/
public class AuthFilter extends ZuulFilter {
@Override
public String filterType() {
//请求之前进行拦截
return "pre";
}
@Override
public int filterOrder() {
//0表示数字越小越优先
return 0;
}
@Override
public boolean shouldFilter() {
return true;
}
//主要是解析token获取用户的身份和权限
@Override
public Object run() throws ZuulException {
//获取上下文
RequestContext ctx = RequestContext.getCurrentContext();
//从安全的上下文中拿到用户的身份对象
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if(!(authentication instanceof OAuth2Authentication)){
// 无token访问网关内资源的情况,目 前仅有uua服务直接暴露
return null;
}
OAuth2Authentication oauth2Authentication = (OAuth2Authentication)authentication;
Authentication userAuthentication = oauth2Authentication.getUserAuthentication();
//1 获取当前用户身份信息
Object principal = userAuthentication.getPrincipal();
//2 获取当前用户的权限
List<String> authorities = new ArrayList();
userAuthentication.getAuthorities().stream()
.forEach(s ->authorities.add(((GrantedAuthority) s)
.getAuthority()));
OAuth2Request oAuth2Request = oauth2Authentication.getOAuth2Request();
Map<String, String> requestParameters = oAuth2Request.getRequestParameters();
Map<String,Object> jsonToken = new HashMap<>(requestParameters);
if(userAuthentication != null){
jsonToken.put("principal",userAuthentication.getName());
jsonToken.put("authorities",authorities);
}
//3 将身份和权限等信息存放到json中,转发给微服务
ctx.addZuulRequestHeader("jsonToken", EncryptUtil.encodeUTF8StringBase64(JSON.toJSONString(jsonToken)));
return null;
}
}
解析格式工具类
package org.dong.oauth.getway.common;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.Base64;
public class EncryptUtil {
private static final Logger logger = LoggerFactory.getLogger(EncryptUtil.class);
public static String encodeBase64(byte[] bytes){
String encoded = Base64.getEncoder().encodeToString(bytes);
return encoded;
}
public static byte[] decodeBase64(String str){
byte[] bytes = null;
bytes = Base64.getDecoder().decode(str);
return bytes;
}
public static String encodeUTF8StringBase64(String str){
String encoded = null;
try {
encoded = Base64.getEncoder().encodeToString(str.getBytes("utf-8"));
} catch (UnsupportedEncodingException e) {
logger.warn("不支持的编码格式",e);
}
return encoded;
}
public static String decodeUTF8StringBase64(String str){
String decoded = null;
byte[] bytes = Base64.getDecoder().decode(str);
try {
decoded = new String(bytes,"utf-8");
}catch(UnsupportedEncodingException e){
logger.warn("不支持的编码格式",e);
}
return decoded;
}
public static String encodeURL(String url) {
String encoded = null;
try {
encoded = URLEncoder.encode(url, "utf-8");
} catch (UnsupportedEncodingException e) {
logger.warn("URLEncode失败", e);
}
return encoded;
}
public static String decodeURL(String url) {
String decoded = null;
try {
decoded = URLDecoder.decode(url, "utf-8");
} catch (UnsupportedEncodingException e) {
logger.warn("URLDecode失败", e);
}
return decoded;
}
public static void main(String [] args){
String str = "abcd{'a':'b'}";
String encoded = EncryptUtil.encodeUTF8StringBase64(str);
String decoded = EncryptUtil.decodeUTF8StringBase64(encoded);
System.out.println(str);
System.out.println(encoded);
System.out.println(decoded);
String url = "== wo";
String urlEncoded = EncryptUtil.encodeURL(url);
String urlDecoded = EncryptUtil.decodeURL(urlEncoded);
System.out.println(url);
System.out.println(urlEncoded);
System.out.println(urlDecoded);
}
}
写一个类配置一下啊上面的filter
package org.dong.oauth.getway.config;
import org.dong.oauth.getway.filter.AuthFilter;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
@Configuration
public class ZuulConfig {
@Bean
public AuthFilter preFileter() {
return new AuthFilter();
}
@Bean
public FilterRegistrationBean corsFilter() {
final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
final CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.addAllowedOrigin("*");
config.addAllowedHeader("*");
config.addAllowedMethod("*");
config.setMaxAge(18000L);
source.registerCorsConfiguration("/**", config);
CorsFilter corsFilter = new CorsFilter(source);
FilterRegistrationBean bean = new FilterRegistrationBean(corsFilter);
bean.setOrder(Ordered.HIGHEST_PRECEDENCE);
return bean;
}
}
修改order
资源微服务需要接收来自网关的token,然后把它解析出来
controller
package org.dong.oauth.order.controller;
import org.dong.oauth.order.pojo.UserDTO;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class OrderController {
@GetMapping(value = "/r1")
@PreAuthorize("hasAnyAuthority('p1')")
public String r1(){
UserDTO user = (UserDTO) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
return user.getUsername()+"访问资源1";
}
@GetMapping(value = "/r2")
@PreAuthorize("hasAnyAuthority('p2')")
public String r2(){
UserDTO user = (UserDTO) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
return "访问资源2";
}
@GetMapping(value = "/r3")
@PreAuthorize("hasAnyAuthority('p3')")
public String r3(){
return "访问资源3";
}
}
解析token
package org.dong.oauth.order.filter;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.dong.oauth.order.common.EncryptUtil;
import org.dong.oauth.order.pojo.UserDTO;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @ClassName TokenAuthenticationFilter
* @Description TODO
* @Author xsh
* @Date 2020-06-13 13:41
* @Version 1.0
**/
@Component
public class TokenAuthenticationFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {
//解析出头中的token
String token = httpServletRequest.getHeader("jsonToken");
if(token!=null){
String json = EncryptUtil.decodeUTF8StringBase64(token);
//将token转成json对象
JSONObject jsonObject = JSON.parseObject(json);
//用户身份信息
// UserDTO userDTO = new UserDTO();
// String principal = jsonObject.getString("principal");
// userDTO.setUsername(principal);
// String principal = jsonObject.getString("principal");
System.out.println(jsonObject.getString("principal"));
UserDTO userDTO = new UserDTO();
userDTO.setUsername(jsonObject.getString("principal"));
//用户权限
JSONArray authoritiesArray = jsonObject.getJSONArray("authorities");
String[] authorities = authoritiesArray.toArray(new String[authoritiesArray.size()]);
//将用户信息和权限填充 到用户身份token对象中
UsernamePasswordAuthenticationToken authenticationToken
= new UsernamePasswordAuthenticationToken(userDTO,null, AuthorityUtils.createAuthorityList(authorities));
authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(httpServletRequest));
//将authenticationToken填充到安全上下文
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
}
filterChain.doFilter(httpServletRequest,httpServletResponse);
}
}
上面需要的两个类如下
package org.dong.oauth.order.common;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.Base64;
public class EncryptUtil {
private static final Logger logger = LoggerFactory.getLogger(EncryptUtil.class);
public static String encodeBase64(byte[] bytes){
String encoded = Base64.getEncoder().encodeToString(bytes);
return encoded;
}
public static byte[] decodeBase64(String str){
byte[] bytes = null;
bytes = Base64.getDecoder().decode(str);
return bytes;
}
public static String encodeUTF8StringBase64(String str){
String encoded = null;
try {
encoded = Base64.getEncoder().encodeToString(str.getBytes("utf-8"));
} catch (UnsupportedEncodingException e) {
logger.warn("不支持的编码格式",e);
}
return encoded;
}
public static String decodeUTF8StringBase64(String str){
String decoded = null;
byte[] bytes = Base64.getDecoder().decode(str);
try {
decoded = new String(bytes,"utf-8");
}catch(UnsupportedEncodingException e){
logger.warn("不支持的编码格式",e);
}
return decoded;
}
public static String encodeURL(String url) {
String encoded = null;
try {
encoded = URLEncoder.encode(url, "utf-8");
} catch (UnsupportedEncodingException e) {
logger.warn("URLEncode失败", e);
}
return encoded;
}
public static String decodeURL(String url) {
String decoded = null;
try {
decoded = URLDecoder.decode(url, "utf-8");
} catch (UnsupportedEncodingException e) {
logger.warn("URLDecode失败", e);
}
return decoded;
}
public static void main(String [] args){
String str = "abcd{'a':'b'}";
String encoded = EncryptUtil.encodeUTF8StringBase64(str);
String decoded = EncryptUtil.decodeUTF8StringBase64(encoded);
System.out.println(str);
System.out.println(encoded);
System.out.println(decoded);
String url = "== wo";
String urlEncoded = EncryptUtil.encodeURL(url);
String urlDecoded = EncryptUtil.decodeURL(urlEncoded);
System.out.println(url);
System.out.println(urlEncoded);
System.out.println(urlDecoded);
}
}
package org.dong.oauth.order.pojo;
import lombok.Data;
/**
* 用户信息
*/
@Data
public class UserDTO {
private Integer id;
private String username;//账号
private String password;
private String realName;//用户名
private String mobile;
}
测试
运行eureak,getway,order,uaa
通过网关进行访问uaa
http://localhost:9003/uaa/oauth/token?client_id=c1&client_secret=secret&grant_type=password&redirect_uri=http://www.baidu.com&username=dong&password=123456
结果
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsicmVzMSJdLCJ1c2VyX25hbWUiOiJkb25nIiwic2NvcGUiOlsiUk9MRV9BRE1JTiIsIlJPTEVfVVNFUiIsIlJPTEVfQVBJIl0sImV4cCI6MTYyMTA3NjU3MSwiYXV0aG9yaXRpZXMiOlsicDEiLCJwMiJdLCJqdGkiOiIwYjQxNDcxNC02NmI2LTRlN2EtOWJiYS1kMzAyYjc0MDc5ZTEiLCJjbGllbnRfaWQiOiJjMSJ9.jnQool3sWTDoogtaAS-K3ioR9JZkx_VamuiRDz7odK4",
"token_type": "bearer",
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsicmVzMSJdLCJ1c2VyX25hbWUiOiJkb25nIiwic2NvcGUiOlsiUk9MRV9BRE1JTiIsIlJPTEVfVVNFUiIsIlJPTEVfQVBJIl0sImF0aSI6IjBiNDE0NzE0LTY2YjYtNGU3YS05YmJhLWQzMDJiNzQwNzllMSIsImV4cCI6MTYyMTMyODU3MSwiYXV0aG9yaXRpZXMiOlsicDEiLCJwMiJdLCJqdGkiOiIyMTM2NTE3MC1iZDFiLTQzNjItOTliNS01ZGY5NDdmYWViZTAiLCJjbGllbnRfaWQiOiJjMSJ9.ji6wkd05HfO619sBB79sNI0cvKWatR3X3SYP2ILO5jM",
"expires_in": 7199,
"scope": "ROLE_ADMIN ROLE_USER ROLE_API",
"jti": "0b414714-66b6-4e7a-9bba-d302b74079e1"
}
我们可以校验一下token信息 post方式
http://localhost:9001/uaa/oauth/check_token
{
"aud": [
"res1"
],
"user_name": "dong",
"scope": [
"ROLE_ADMIN",
"ROLE_USER",
"ROLE_API"
],
"exp": 1621076571,
"authorities": [
"p1",
"p2"
],
"jti": "0b414714-66b6-4e7a-9bba-d302b74079e1",
"client_id": "c1"
}
通过网关去访问资源服务 (访问r3没有权限)
http://localhost:9003/order/r1
dong访问资源1
改进
上面我们通过token只获取到了用户名,原因是在网关的AuthFilter类中
if(userAuthentication != null){
jsonToken.put("principal",userAuthentication.getName());
jsonToken.put("authorities",authorities);
}
一个简单的改法,就是拥有principal存一个用户的所有信息(具体步骤:略)
//取出用户身份信息
String principal = userJson.getString("principal");
//将json转成对象
UserDTO userDTO = JSON.parseObject(principal, UserDTO.class);
参考教程:黑马
完整代码:https://gitee.com/dongjixue/spring-security-and-oauth2.0