用户认证与授权(登录功能)

截至目前,项目已经完成了在线学习功能,用户通过在线学习页面点播视频进行学习。如何去记录学生的学习过程呢?要想掌握学生的学习情况就需要知道用户的身份信息,记录哪个用户在什么时间学习什么课程;如果用户要购买课程也需要知道用户的身份信息。所以,去管理学生的学习过程最基本的要实现用户的身份认证。
什么是用户身份认证?
用户身份认证即用户去访问系统资源时系统要求验证用户的身份信息,身份合法方可继续访问。常见的用户身份认证表现形式有:用户名密码登录,指纹打卡等方式。
什么是用户授权?
用户认证通过后去访问系统的资源,系统会判断用户是否拥有访问资源的权限,只允许访问有权限的系统资源,没有权限的资源将无法访问,这个过程叫用户授权。

本项目包括多个子项目(微服务),如:学习系统,教学管理中心、系统管理中心等,为了提高用户体验性需要实现用户只认证一次便可以在多个拥有访问权限的系统中访问,这个功能叫做单点登录。

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

一、 Spring security Oauth2认证解决方案
搭建认证服务器
创建xc-service-ucenter-auth工程,该工程是基于Spring Security Oauth2的一个二次封装的工程。

创建用户数据库
在这里插入图片描述
以“oauth_”开头的表都是spring Security 自带的表。
本项目中spring Security 主要使用oauth_client_details表:
在这里插入图片描述
client_id:客户端id
resource_ids:资源id(暂时不用)
client_secret:客户端密码
scope:范围
access_token_validity:访问token的有效期(秒)
refresh_token_validity:刷新token的有效期(秒)
authorized_grant_type:授权类型,authorization_code,password,refresh_token,client_credentials

Oauth2授权模式
Oauth2有以下授权模式: 授权码模式(Authorization Code) 隐式授权模式(Implicit) 密码模式(Resource Owner Password Credentials) 客户端模式(Client Credentials) 其中授权码模式和密码模式应用较多。
密码模式与授权码模式的区别是申请令牌不再使用授权码,而是直接通过用户名和密码即可申请令牌。
Oauth2授权码模式和密码模式的使用教程见讲义。

本项目使用密码模式。

二、资源服务授权
资源服务授权流程
在这里插入图片描述
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 PUBLIC_KEY = "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(); 
	} 
}

JWT介绍
在介绍JWT之前先看一下传统校验令牌的方法,如下图:
在这里插入图片描述
问题:
传统授权方法的问题是用户每次请求资源服务,资源服务都需要携带令牌访问认证服务去校验令牌的合法性,并根据令牌获取用户的相关信息,性能低下。
解决:
使用JWT的思路是,用户认证通过会得到一个JWT令牌,JWT令牌中已经包括了用户相关的信息,客户端只需要携带JWT访问资源服务,资源服务根据事先约定的算法自行完成令牌校验(使用公钥),无需每次都请求认证服务完成授权。
JWT令牌授权过程如下图:
在这里插入图片描述
JWT令牌结构
JWT令牌由三部分组成,每部分中间使用点(.)分隔,比如:xxxxx.yyyyy.zzzzz。
Header 头部包括令牌的类型(即JWT)及使用的哈希算法(如HMAC SHA256或RSA),
例子如下:

{
	"alg": "HS256", 
	"typ": "JWT" 
}

将上边的内容使用Base64Url编码,得到一个字符串就是JWT令牌的第一部分。
Payload
第二部分是负载,内容也是一个json对象,它是存放有效信息的地方,它可以存放jwt提供的现成字段,比 如:iss(签发者),exp(过期时间戳), sub(面向的用户)等,也可自定义字段。 此部分不建议存放敏感信息,因为此部分可以解码还原原始内容。 最后将第二部分负载使用Base64Url编码,得到一个字符串就是JWT令牌的第二部分。
Signature
第三部分是签名,此部分用于防止jwt内容被篡改。 这个部分使用base64url将前两部分进行编码,编码后使用点(.)连接组成字符串,最后使用header中声明 签名算法进行签名。
一个例子:

HMACSHA256( base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)

base64UrlEncode(header):jwt令牌的第一部分。 base64UrlEncode(payload):jwt令牌的第二部分。 secret:签名所使用的密钥。
Spring Security 提供JwtHelper来实现创建JWT令牌,校验JWT令牌等操作。

三、认证接口开发
在这里插入图片描述
执行流程:
1、用户登录,请求认证服务
2、认证服务认证通过,生成jwt令牌,将jwt令牌及相关信息写入Redis,并且将身份令牌写入cookie
3、用户访问资源页面,带着cookie到网关
4、网关从cookie获取token,并查询Redis校验token,如果token不存在则拒绝访问,否则放行
5、用户退出,请求认证服务,清除redis中的token,并且删除cookie中的token
使用redis存储用户的身份令牌有以下作用: 1、实现用户退出注销功能,服务端清除令牌后,即使客户端请求携带token也是无效的。 2、由于jwt令牌过长,不宜存储在cookie中,所以将jwt令牌存储在redis,由客户端请求服务端获取并在客户端存储。

下一篇继续。

  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值