Spring security + Oauth2认证解决方案:项目配置及测试

本项目采用 Spring security + Oauth2完成用户认证及用户授权,Spring security 是一个强大的和高度可定制的身
份验证和访问控制框架,Spring security 框架集成了Oauth2协议,下图是项目认证架构图:

1、用户请求认证服务完成认证。
2、认证服务下发用户身份令牌,拥有身份令牌表示身份合法。
3、用户携带令牌请求资源服务,请求资源服务必先经过网关。
4、网关校验用户身份令牌的合法,不合法表示用户没有登录,如果合法则放行继续访问。
5、资源服务获取令牌,根据令牌完成授权。
6、资源服务完成授权则响应资源信息。

Oauth2授权码模式

Oauth2授权模式

Oauth2有以下授权模式:
授权码模式(Authorization Code)
隐式授权模式(Implicit)
密码模式(Resource Owner Password Credentials)
客户端模式(Client Credentials)
其中授权码模式和密码模式应用较多,本小节介绍授权码模式。

授权码授权流程

上边例举的黑马程序员网站使用微信认证的过程就是授权码模式,流程如下:
1、客户端请求第三方授权
2、用户(资源拥有者)同意给客户端授权
3、客户端获取到授权码,请求认证服务器申请令牌
4、认证服务器向客户端响应令牌
5、客户端请求资源服务器的资源,资源服务校验令牌合法性,完成授权
6、资源服务器返回受保护资源

申请授权码

请求认证服务获取授权码:
Get请求:

curl localhost:40400/auth/oauth/authorize?client_id=XcWebApp&response_type=code&scop=app&redirect_uri=http://localhost

参数列表如下:

  • client_id:客户端id,和授权配置类中设置的客户端id一致。
  • response_type:授权码模式固定为code
  • scop:客户端范围,和授权配置类中设置的scop一致。
  • redirect_uri:跳转uri,当授权码申请成功后会跳转到此地址,并在后边带上code参数(授权码)。
    首先跳转到登录页面:

在这里插入图片描述

输入账号和密码,点击Login。
Spring Security接收到请求会调用UserDetailsService接口的loadUserByUsername方法查询用户正确的密码。
当前导入的基础工程中将正确的密码硬编码为“123”,所以这里账号随意输入,密码输入123即可认证通过。
接下来进入授权页面:
在这里插入图片描述

点击“同意”。
接下来返回授权码:
认证服务携带授权码跳转redirecturi
在这里插入图片描述

申请令牌

拿到授权码后,申请令牌。
Post请求:http://localhost:40400/auth/oauth/token
参数如下:

  • grant_type:授权类型,填写authorization_code,表示授权码模式
  • code:授权码,就是刚刚获取的授权码,注意:授权码只使用一次就无效了,需要重新申请。
  • redirect_uri:申请授权码时的跳转url,一定和申请授权码时用的redirect_uri一致。
    此链接需要使用 http Basic认证。
    什么是http Basic认证?
    http协议定义的一种认证方式,将客户端id和客户端密码按照“客户端ID:客户端密码”的格式拼接,并用base64编
    码,放在header中请求服务端,一个例子:
    Authorization:Basic WGNXZWJBcHA6WGNXZWJBcHA=WGNXZWJBcHA6WGNXZWJBcHA=用户名:密码的base64编码。
    认证失败服务端返回 401 Unauthorized
    以上测试使用postman完成:
    http basic认证:
    在这里插入图片描述
    客户端Id和客户端密码会匹配数据库oauthclientdetails表中的客户端id及客户端密码。
    Post请求参数:
    在这里插入图片描述
    点击发送:
    申请令牌成功:
    在这里插入图片描述
    access_token:访问令牌,携带此令牌访问资源
    token_type:有MAC Token与Bearer Token两种类型,两种的校验算法不同,RFC 6750建议Oauth2采用 Bearer Token(http://www.rfcreader.com/#rfc6750)。
    refresh_token:刷新令牌,使用此令牌可以延长访问令牌的过期时间。
    expires_in:过期时间,单位为秒。
    scope:范围,与定义的客户端范围一致。

资源服务授权

资源服务授权流程
资源服务拥有要访问的受保护资源,客户端携带令牌访问资源服务,如果令牌合法则可成功访问资源服务中的资源,如下图:
在这里插入图片描述

上图的业务流程如下:
1、客户端请求认证服务申请令牌
2、认证服务生成令牌
认证服务采用非对称加密算法,使用私钥生成令牌。
3、客户端携带令牌访问资源服务
客户端在Http header 中添加: Authorization:Bearer 令牌。
4、资源服务请求认证服务校验令牌的有效性
资源服务接收到令牌,使用公钥校验令牌的合法性。
5、令牌有效,资源服务向客户端响应资源信息

资源服务授权配置
基本上所有微服务都是资源服务,这里我们在课程管理服务上配置授权控制,当配置了授权控制后如要访问课程信息则必须提供令牌。
1、配置公钥
认证服务生成令牌采用非对称加密算法,认证服务采用私钥加密生成令牌,对外向资源服务提供公钥,资源服务使用公钥来校验令牌的合法性。
将公钥拷贝到 publickey.txt文件中,将此文件拷贝到资源服务工程的classpath下
在这里插入图片描述

2、添加依赖

<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring‐cloud‐starter‐oauth2</artifactId>
</dependency>

3、在config包下创建ResourceServerConfig类:

@Configuration
@EnableResourceServer
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)//激活方法上的
PreAuthorize注解
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
    
    
	//公钥
	private static final String PUBLICKEY = "publickey.txt";
	//定义JwtTokenStore,使用jwt令牌
	@Bean
	public TokenStore tokenStore(JwtAccessTokenConverter jwtAccessTokenConverter) {
    
    
		return new JwtTokenStore(jwtAccessTokenConverter);
	}
	//定义JJwtAccessTokenConverter,使用jwt令牌
	@Bean
	public JwtAccessTokenConverter jwtAccessTokenConverter() {
    
    
		JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
		converter.setVerifierKey(getPubKey());
		return converter;
	}
	/**
	* 获取非对称加密公钥 Key
	* @return 公钥 Key
	*/
	private String getPubKey() {
    
    
		Resource resource = new ClassPathResource(PUBLIC_KEY);
		try {
    
    
			InputStreamReader inputStreamReader = new
			InputStreamReader(resource.getInputStream());
			BufferedReader br = new BufferedReader(inputStreamReader);
			return br.lines().collect(Collectors.joining("\n"));
		} catch (IOException ioe) {
    
    
			return null;
		}
	}
	//Http安全配置,对每个到达系统的http请求链接进行校验
	@Override
	public void configure(HttpSecurity http) throws Exception {
    
    
		//所有请求必须认证通过
		http.authorizeRequests().anyRequest().authenticated();
	}
}

资源服务授权测试

这里我们测试课程图片查询

get http://localhost:31200/course/coursepic/list/4028e58161bd3b380161bd3bcd2f0000

请求时没有携带令牌则报错:

{
    
    
	"error": "unauthorized",
	"error_description": "Full authentication is required to access this resource"
}

请求时携带令牌:
在http header中添加 Authorization: Bearer 令牌
在这里插入图片描述

当输入错误的令牌也无法正常访问资源。

在这里插入图片描述

解决swagger-ui无法访问

当课程管理加了授权之后再访问swagger-ui则报错:
在这里插入图片描述
修改授权配置类ResourceServerConfig的configure方法:
针对swagger-ui的请求路径进行放行:

//Http安全配置,对每个到达系统的http请求链接进行校验
@Override
public void configure(HttpSecurity http) throws Exception {
    
    
	//所有请求必须认证通过
	http.authorizeRequests()
	//下边的路径放行
	.antMatchers("/v2/api‐docs", "/swagger‐resources/configuration/ui",
	"/swagger‐resources","/swagger‐resources/configuration/security",
	"/swagger‐ui.html","/webjars/**").permitAll()
	.anyRequest().authenticated();
}

注意:
通过上边的配置虽然可以访问swagger-ui,但是无法进行单元测试,除非去掉认证的配置或在上边配置中添加所有
请求均放行(“/**”)。

猜你喜欢

转载自blog.csdn.net/a772304419/article/details/132084122