spring cloud oauth2.0 鉴权

本贴最后更新于 1557 天前,其中的信息可能已经事过景迁

spring cloud oauth2.0 鉴权

标签(空格分隔): springcloud oauth 鉴权


[TOC]

1.概述

文章主要是描述 springcloud 的一个鉴权,利用 oauth2.0 和 security 实现,所以也继承了 security 的权限框架,粒度可以达到按钮级别,具体还是要看设计思路

这里会介绍 3 种的 token 存储方式,(基于内存,基于 redis,基于 jwt)

还有两种 client 的配置方式,一种是采用官方数据库进行初始化,另一种是写在代码内存中。

2.实现流程

在这简单的说一下,不说的那么复杂。一个注册中心,一个鉴权的服务(我暂时把用户也放在鉴权服务里了,你若是喜欢也可以单独分出去),一个 A 服务(就几个简单的 controller 接口)。

项目启动后,用户通过/oauth/token 获取到 access_token,然后通过 access_token 可以请求具体接口,在资源服务器(也就是 A 服务)的配置文件中可以加入一个获取用户信息的配置项,这样就可以把用户信息获取得到,进行权限的判断。

暂时没有用网关去做 oauth2.0 的统一验证,我觉得网关还是只做转发路由,具体还是看情况吧。

3.代码实现

3.1 注册中心 eureka

这个没什么好说的,我用的是 springboot2.0.4 版本,cloud 版本为 Finchley.RELEASE

server:
  port : 8761
eureka:
  instance:
    hostname : localhost
  client:
    registerWithEureka : false
    fetchRegistry : false
    serviceUrl:
      defaultZone : http://${eureka.instance.hostname}:${server.port}/eureka/

3.2 资源服务器

配置文件

spring:
  application:
    name: oauth-a
  mvc:
    servlet:
      load-on-startup: 1   #初始化加载,不用懒加载
server:
  port: 8888
eureka:
  client:
    serviceUrl:
      defaultZone: http://127.0.0.1:8761/eureka/
    registry-fetch-interval-seconds: 5
  instance:
    lease-expiration-duration-in-seconds: 15
    lease-renewal-interval-in-seconds: 5
    prefer-ip-address: true
    instance-id: ${spring.application.name}:${server.port}
logging:
  level:
    root: info
security:
  oauth2:
    resource:
      user-info-uri: http://127.0.0.1:7777/user/user-me
      prefer-token-info: false

主要是看后面一段 security 配置

配置了一个资源访问的地址,通过这个接口可以获取到登录的用户信息,而这个用户里面的信息包含的内容,要看你在登录的时候设置了什么了,具体看下面的鉴权的服务,一般会在里面返回所有角色信息和权限信息,在security的权限框架中,没有把角色和权限分开,都是统一用的一个集合,所以在角色里要默认加一个ROLE的前缀,如(ROLE_ADMIN,ROLE_USER)

security.oauth2.resource.user-info-uri:配置userinfo的url地址
security.oauth2.resource.token-info-uri:配置check-token的url地址;
security.oauth2.resource.prefer-token-info=true,如果上面两个都配置了,更倾向于用哪个

然后我们看一下主要的资源服务器配置:
ResourceServerConfig.java

package com.example.oautha.config;

import java.util.HashMap;

import javax.servlet.http.HttpServletResponse;
import org.springframework.http.MediaType;
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.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;

import com.fasterxml.jackson.databind.ObjectMapper;

/**
 * 资源服务配置
 *
 */
@EnableResourceServer
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {

    @SuppressWarnings({ "unchecked", "rawtypes", "serial" })
	@Override
    public void configure(HttpSecurity http) throws Exception {
        http.csrf().disable().exceptionHandling()
                .authenticationEntryPoint((req, resp, exception) -> {
                    resp.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
                    resp.getWriter().write(new ObjectMapper().writeValueAsString(new HashMap() {{
                        put("status", 0);
                        put("error", "没有权限");
                    }}));
                })
                .and().authorizeRequests()
                .antMatchers("/anon/**").permitAll() // 放开权限的url
                .anyRequest().authenticated().and().httpBasic();

        http.headers().frameOptions().sameOrigin();
    }

}

中间有一个自定义的返回信息设置,看大家喜好,也可以不要。

然后是上面有一个注解 @EnableGlobalMethodSecurity(prePostEnabled = true),开启这个注解为 true,才可以使用 security 的权限控制。如下面的 controller

TestController.java

package com.example.oautha.controller;

import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class TestController {

	@RequestMapping("/anon/test")
	public String anon(String param) {
		return "/anon/test:"+param;
	}
	
	@RequestMapping("/auth/test")
	public String auth(String param) {
		return "/auth/test:"+param;
	}
	
	@RequestMapping("/auth/test1")
	@PreAuthorize("hasRole('ROLE_USER')")
	public String auth1(String param) {
		return "/auth/test1";
	}
	
	@RequestMapping("/auth/test2")
	@PreAuthorize("hasRole('ROLE_ADMIN')")
	public String auth2(String param) {
		return "/auth/test2";
	}
	
}

@PreAuthorize("hasRole('ROLE_ADMIN')") 注解就可以做到权限的控制,这是判断角色的,还有判断具体权限的,如:

@PreAuthorize("hasAuthority('mail:query')")
@PreAuthorize("hasAnyAuthority('back:menu:set2role','menu:byroleid')")

3.3 授权服务器

首先看用户登录这一块:

@Service("userDetailsServiceImpl")
public class UserDetailsServiceImpl implements UserDetailsService {

    @Autowired
    private UserDao userDao;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        User user = userDao.findByUsername(username);
        if (user == null) {
            throw new AuthenticationCredentialsNotFoundException("用户不存在");
        } 
        return user;
    }

}

这是重写了框架自带的一个加载方法,密码校验框架底层做了判断,哦我们只要把信息输入进去就行,而角色和权限信息在此时也需要设置进去,在这里的 User 类是实现了 UserDetails 接口的,如:

@Data
public class User implements UserDetails{

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	private Long id;
	private String username;
	private String password;
	
	@Override
	public Collection<? extends GrantedAuthority> getAuthorities() {
		//默认给一个用户角色,生产环境自己添加相应的角色和权限
		return AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_USER");
	}
	@Override
	public boolean isAccountNonExpired() {
		//判断用户是否过期,默认为true,生产环境视情况修改,赋值
		return true;
	}
	@Override
	public boolean isAccountNonLocked() {
		//判断用户是否被锁定,默认为true,生产环境视情况修改,赋值
		return true;
	}
	@Override
	public boolean isCredentialsNonExpired() {
		//判断用户凭证是否过期,默认为true,生产环境视情况修改,赋值
		return true;
	}
	@Override
	public boolean isEnabled() {
		//判断用户是否启用,默认为true,生产环境视情况修改,赋值
		return true;
	}
	
}

然后我们看最重要的授权配置

3.3.1 内存存储

package com.example.user.config;

import javax.sql.DataSource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.client.JdbcClientDetailsService;
import org.springframework.security.oauth2.provider.token.store.InMemoryTokenStore;

/**
 * 授权服务器配置
 *
 */
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfigInMemory extends AuthorizationServerConfigurerAdapter {

	@Autowired
	private AuthenticationManager authenticationManager;

	@Autowired
	private DataSource dataSource;
	
	@Autowired
    public BCryptPasswordEncoder bCryptPasswordEncoder;
	
	@Autowired
	public UserDetailsService userDetailsServiceImpl;
	
	/**
	 * 配置token的数据源、自定义的tokenServices等信息
	 * 配置身份认证器,配置认证方式,TokenStore,TokenGranter,OAuth2RequestFactory
	 * 
	 */
	@Override
	public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
		endpoints
			.authenticationManager(authenticationManager)
			.tokenStore(new InMemoryTokenStore())
			.userDetailsService(userDetailsServiceImpl);
	}

	/**
	 * 配置安全策略
	 * 对应于配置AuthorizationServer安全认证的相关信息,创建ClientCredentialsTokenEndpointFilter核心过滤器
	 * 
	 */
	@Override
	public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
		security.allowFormAuthenticationForClients();//允许表单提交client信息
		security.tokenKeyAccess("permitAll()");
		security.checkTokenAccess("isAuthenticated()");//allow check token
	}

	/**
	 * 配置客户端认证信息
	 * 配置OAuth2的客户端相关信息,client信息包括:clientId、secret、scope、authorizedGrantTypes
	 */
	@Override
	public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
		//基于oauth_client_token表的操作
		clients.withClientDetails(new JdbcClientDetailsService(dataSource));

		//基于内存
		/*clients.inMemory().withClient("system") // client_id
				.secret(bCryptPasswordEncoder.encode("system")) // client_secret
				.authorizedGrantTypes("authorization_code", "password") // 该client允许的授权类型
				.scopes("app"); // 允许的授权范围
		 */
	}

}

3.3.2jwt 存储

package com.example.user.config;

import javax.sql.DataSource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.client.JdbcClientDetailsService;
import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
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
@EnableAuthorizationServer
public class AuthorizationServerConfigJwt extends AuthorizationServerConfigurerAdapter {

	@Autowired
	private AuthenticationManager authenticationManager;
	@Autowired
	private DataSource dataSource;
	@Autowired
    public BCryptPasswordEncoder bCryptPasswordEncoder;
	@Autowired
	public UserDetailsService userDetailsServiceImpl;
	
	@Bean
    public TokenStore tokenStore() {
        return new JwtTokenStore(jwtAccessTokenConverter());
    }
	
	@Bean
    @Primary
    public DefaultTokenServices tokenServices() {
        DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
        defaultTokenServices.setTokenStore(tokenStore());
        defaultTokenServices.setSupportRefreshToken(true);
        return defaultTokenServices;
    }
	
	@Bean
    public JwtAccessTokenConverter jwtAccessTokenConverter() {
       /* KeyStoreKeyFactory keyStoreKeyFactory = new KeyStoreKeyFactory(new ClassPathResource("test-jwt.jks"), "test123".toCharArray());
        JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
        converter.setKeyPair(keyStoreKeyFactory.getKeyPair("test-jwt"));
        return converter;*/
		JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
		// JWT签名
		converter.setSigningKey("0123456789");
		return converter;
    }
	
	/**
	 * 配置token的数据源、自定义的tokenServices等信息
	 * 配置身份认证器,配置认证方式,TokenStore,TokenGranter,OAuth2RequestFactory
	 * 
	 */
	@Override
	public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
		endpoints
			.authenticationManager(authenticationManager)
			.tokenStore(tokenStore())
			.accessTokenConverter(jwtAccessTokenConverter())
			.userDetailsService(userDetailsServiceImpl);
	}

	/**
	 * 配置安全策略
	 * 对应于配置AuthorizationServer安全认证的相关信息,创建ClientCredentialsTokenEndpointFilter核心过滤器
	 * 
	 */
	@Override
	public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
		security.allowFormAuthenticationForClients();//允许表单提交client信息
		security.tokenKeyAccess("permitAll()");
		security.checkTokenAccess("isAuthenticated()");//allow check token
	}

	/**
	 * 配置客户端认证信息
	 * 配置OAuth2的客户端相关信息,client信息包括:clientId、secret、scope、authorizedGrantTypes
	 */
	@Override
	public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
		//基于oauth_client_token表的操作
		clients.withClientDetails(new JdbcClientDetailsService(dataSource));

		//基于内存
		/*clients.inMemory().withClient("system") // client_id
				.secret(bCryptPasswordEncoder.encode("system")) // client_secret
				.authorizedGrantTypes("authorization_code", "password") // 该client允许的授权类型
				.scopes("app"); // 允许的授权范围
		 */
	}

}

3.3.3redis 存储

package com.example.user.config;

import javax.sql.DataSource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.client.JdbcClientDetailsService;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStore;

/**
 * 授权服务器配置
 *
 */
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfigRedis extends AuthorizationServerConfigurerAdapter {

	@Autowired
	private AuthenticationManager authenticationManager;
	@Autowired
	private DataSource dataSource;
	@Autowired
    public BCryptPasswordEncoder bCryptPasswordEncoder;
	@Autowired
    private RedisConnectionFactory redisConnectionFactory;
	@Autowired
	public UserDetailsService userDetailsServiceImpl;
	
	@Bean
    public TokenStore tokenStore() {
        return new RedisTokenStore(redisConnectionFactory);
    }
	
	/**
	 * 配置token的数据源、自定义的tokenServices等信息
	 * 配置身份认证器,配置认证方式,TokenStore,TokenGranter,OAuth2RequestFactory
	 * 
	 */
	@Override
	public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
		endpoints
			.authenticationManager(authenticationManager)
			.tokenStore(tokenStore())
			.userDetailsService(userDetailsServiceImpl);
	}

	/**
	 * 配置安全策略
	 * 对应于配置AuthorizationServer安全认证的相关信息,创建ClientCredentialsTokenEndpointFilter核心过滤器
	 * 
	 */
	@Override
	public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
		security.allowFormAuthenticationForClients();//允许表单提交client信息
		security.tokenKeyAccess("permitAll()");
		security.checkTokenAccess("isAuthenticated()");//allow check token
	}

	/**
	 * 配置客户端认证信息
	 * 配置OAuth2的客户端相关信息,client信息包括:clientId、secret、scope、authorizedGrantTypes
	 */
	@Override
	public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
		//基于oauth_client_token表的操作
		clients.withClientDetails(new JdbcClientDetailsService(dataSource));

		//基于内存
		/*clients.inMemory().withClient("system") // client_id
				.secret(bCryptPasswordEncoder.encode("system")) // client_secret
				.authorizedGrantTypes("authorization_code", "password") // 该client允许的授权类型
				.scopes("app"); // 允许的授权范围
		 */
	}

}

其实我们可以看出,主要的不同就是在于 AuthorizationServerEndpointsConfigurer endpoints 的配置不同,这里是用来配置 token 的数据源、自定义的 tokenServices 等信息,也就是对令牌存储,认证的。而 AuthorizationServerSecurityConfigurer security 的安全认证比较简单,授权一下表单提交和 token 认证即可,
再是 client 的 ClientDetailsServiceConfigurer clients 配置信息,
一种是官方自带的一个数据库 oauth_client_token,一种是写在内存中,可以放在配置文件中读取。

接着我们看一下授权服务器的资源配置,因为在授权服务器也会存在一些需要获取的资源,所以也需要一些简单的配置,以及安全认证也是一样,如下两个类:

ResourceServerConfig.java

package com.example.user.config;

import java.util.HashMap;

import javax.servlet.http.HttpServletRequest;

import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.web.util.matcher.RequestMatcher;

import com.fasterxml.jackson.databind.ObjectMapper;

/**
 * 资源服务配置<br>
 * 
 * 注解@EnableResourceServer帮我们加入了org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationProcessingFilter<br>
 * 该filter帮我们从request里解析出access_token<br>
 * 并通过org.springframework.security.oauth2.provider.token.DefaultTokenServices根据access_token和认证服务器配置里的TokenStore从redis或者jwt里解析出用户
 * 
 * 注意认证中心的@EnableResourceServer和别的微服务里的@EnableResourceServer有些不同<br>
 * 别的微服务是通过org.springframework.boot.autoconfigure.security.oauth2.resource.UserInfoTokenServices来获取用户的
 * 
 */
@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {

	@SuppressWarnings("serial")
	@Override
	public void configure(HttpSecurity http) throws Exception {
		http.requestMatcher(new OAuth2RequestedMatcher()).csrf().disable().exceptionHandling()
				.authenticationEntryPoint((req, resp, exception) -> {
					resp.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
					resp.getWriter().write(new ObjectMapper().writeValueAsString(new HashMap<String, String>() {
						{
							put("status", "401");
							put("error", "ResourceServerConfigurerAdapter认证失败");
						}
					}));
				}).and().authorizeRequests().antMatchers().permitAll().anyRequest().authenticated();
	}

	/**
	 * 判断来源请求是否包含oauth2授权信息<br>
	 * url参数中含有access_token,或者header里有Authorization
	 */
	private static class OAuth2RequestedMatcher implements RequestMatcher {
		@Override
		public boolean matches(HttpServletRequest request) {
			// 请求参数中包含access_token参数
			if (request.getParameter(OAuth2AccessToken.ACCESS_TOKEN) != null) {
				return true;
			}
			// 头部的Authorization值以Bearer开头
			String auth = request.getHeader("Authorization");
			if (auth != null) {
				return auth.startsWith(OAuth2AccessToken.BEARER_TYPE);
			}
			return false;
		}
	}

}

SecurityConfig.java

package com.example.user.config;

import java.util.HashMap;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.http.MediaType;
import org.springframework.security.authentication.AuthenticationManager;
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.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

import com.fasterxml.jackson.databind.ObjectMapper;

/**
 * spring security配置
 * 
 */
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

	@Autowired
	public UserDetailsService userDetailsServiceImpl;

	@Bean
	public BCryptPasswordEncoder passwordEncoder() {
		return new BCryptPasswordEncoder();
	}

	@Bean
	@Override
	public AuthenticationManager authenticationManagerBean() throws Exception {
		return super.authenticationManagerBean();
	}

	/**
	 * http安全配置
	 * 
	 * @param http
	 * @throws Exception
	 */
	@SuppressWarnings("serial")
	@Override
	protected void configure(HttpSecurity http) throws Exception {
		http.httpBasic().and().csrf().disable().exceptionHandling().authenticationEntryPoint((req, resp, exception) -> {
			resp.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
			resp.getWriter().write(new ObjectMapper().writeValueAsString(new HashMap<String, String>(2) {
				{
					put("status", "401");
					put("error", "WebSecurityConfigurerAdapter认证失败");
				}
			}));
		}).and().authorizeRequests().antMatchers().permitAll().anyRequest().authenticated();
	}

}

这里没有太多的描述,相比于文字,我还是更喜欢直接代码运行跑起来后,一边看运行情况,一边了解原理,看自己的学习方式而定吧。

然后看一下 controller,这里有一个前面配置文件中请求的接口信息,就是获取用户的信息,检验 token 的那个

package com.example.user.controller;

import java.security.Principal;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.example.user.model.User;
import com.example.user.service.UserService;

@RestController
@RequestMapping("/user")
public class UserController {

	@Autowired
	private UserService userService;
	
	@GetMapping("/findByUsername")
	public User findByUsername(String username) {
		return userService.findByUsername(username);
	}
	
	@GetMapping("/user-me")
    public Principal user(Principal member) {
        //获取当前用户信息
        return member;
    }
	
	@RequestMapping("/auth/test")
	public String auth(String param) {
		return "/auth/test:"+param;
	}
	
	@RequestMapping("/auth/test1")
	@PreAuthorize("hasRole('ROLE_USER')")
	public String auth1(String param) {
		return "/auth/test1";
	}
	
	@RequestMapping("/auth/test2")
	@PreAuthorize("hasRole('ROLE_ADMIN')")
	public String auth2(String param) {
		return "/auth/test2";
	}
}

主要看这里

	@GetMapping("/user-me")
    public Principal user(Principal member) {
        //获取当前用户信息
        return member;
    }

4.演示效果

这里我用的是 postman 模拟请求

4.1 请求授权服务

1.请求 token

此处输入图片的描述

2.刷新 token

此处输入图片的描述

4.2 请求 A 服务

1.请求 anon 公开接口

此处输入图片的描述

2.请求 test2 接口(拥有 admin 角色才可以)

此处输入图片的描述

2.请求 test1 接口(拥有 user 角色才可以)

此处输入图片的描述

5.添加 zuul 网关

zuul 网关最好的就是只做路由,具体的权限还是由各自的资源服务器处理,个人理解,不喜勿喷

@Configuration
@EnableOAuth2Sso
public class SecurityConfig extends WebSecurityConfigurerAdapter{

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable();
    }
}
spring:
  application:
    name: oauth-zuul
server:
  port: 9030
eureka:
  instance:
    prefer-ip-address: true #使用IP注册
    instance-id: ${spring.application.name}:${server.port}
  client:
      service-url:
        defaultZone: http://localhost:8761/eureka/
zuul:
  host:
    connect-timeout-millis: 10000
    socket-timeout-millis: 60000
  routes:
    oauth-center:
      path: /uaa/**
      strip-prefix: true
      sensitiveHeaders:
      serviceId: oauth-center
    oauth-a:
      path: /oa/**
      strip-prefix: true
      sensitiveHeaders:
      serviceId: oauth-a
security:
  oauth2:
    client:
      access-token-uri: http://localhost:9030/uaa/oauth/token ##网关的地址
      user-authorization-uri: http://localhost:9030/uaa/oauth/authorize
      #client-id: system #OAuth2客户端ID
      #client-secret: system #OAuth2客户端密钥
    resource:
      user-info-uri:  http://localhost:9030/uaa/user/user-me
      prefer-token-info: false
      #jwt:
        #key-value: 0123456789 #使

gitee 源码地址

  • 云计算
    77 引用 • 91 回帖 • 1 关注
  • OAuth

    OAuth 协议为用户资源的授权提供了一个安全的、开放而又简易的标准。与以往的授权方式不同之处是 oAuth 的授权不会使第三方触及到用户的帐号信息(如用户名与密码),即第三方无需使用用户的用户名与密码就可以申请获得该用户资源的授权,因此 oAuth 是安全的。oAuth 是 Open Authorization 的简写。

    36 引用 • 103 回帖 • 9 关注
  • 鉴权
    2 引用

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...