首页 » SEO优化 » 指纹打卡php技巧_学成在线第16天教材 Spring Security Oauth2 JWT

指纹打卡php技巧_学成在线第16天教材 Spring Security Oauth2 JWT

访客 2024-11-30 0

扫一扫用手机浏览

文章目录 [+]

截至目前,项目已经完成了在线学习功能,用户通过在线学习页面点播视频进行学习。
如何去记录学生的学习过程 呢?要想节制学生的学习情形就须要知道用户的身份信息,记录哪个用户在什么韶光学习什么课程;如果用户要购 买课程也须要知道用户的身份信息。
以是,去管理学生的学习过程最基本的要实现用户的身份认证。

什么是用户身份认证?

指纹打卡php技巧_学成在线第16天教材 Spring Security Oauth2 JWT

用户身份认证即用户去访问系统资源时系统哀求验证用户的身份信息,身份合法方可连续访问。
常见的用户身份认 证表现形式有:用户名密码登录,指纹打卡等办法。

指纹打卡php技巧_学成在线第16天教材 Spring Security Oauth2 JWT
(图片来自网络侵删)

什么是用户授权?

用户认证通过后去访问系统的资源,系统会判断用户是否拥有访问资源的权限,只许可访问有权限的系统资源,没 有权限的资源将无法访问,这个过程叫用户授权。

1.2单点登录需求

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

引用百度百科:单点登录(Single Sign On),简称为 SSO,是目前比较盛行的企业业务整合的办理方案之一。
SSO的定义是在多个运用系统中,用户只须要登录一次就可以访问所有相互信赖的运用系统。

下图是SSO的示意图,用户登录学成网一次即可访问多个别系。

1.3第三方认证需求

作为互联网项目难免须要访问外部系统的资源,同样本系统也要访问第三方系统的资源接口,一个场景如下:

一个微信用户没有在学成在线注册,本系统可以通过要求微信系统来验证该用户的身份,验证通过后该用户便可在 本系统学习,它的基本流程如下:

从上图可以看出,微信不属于本系统,本系统并没有存储微信用户的账号、密码等信息,本系统如果要获取该用户 的基本信息则须要首先通过微信的认证系统(微信认证)进行认证,微信认证通过后本系统便可获取该微信用户的 基本信息,从而在本系统将该微信用户的头像、昵称等信息显示出来,该用户便不用在本系统注册却可以直接学 习。

什么是第三方认证(跨平台认证)?

当须要访问第三方系统的资源时须要首先通过第三方系统的认证(例如:微信认证),由第三方系统对用户认证通 过,并授权资源的访问权限。

2用户认证技能方案

2.1单点登录技能方案

分布式系统要实现单点登录,常日将认证系统独立抽取出来,并且将用户身份信息存储在单独的存储介质,比如:

MySQL、Redis,考虑性能哀求,常日存储在Redis中,如下图

单点登录的特点是:

1、认证系统为独立的系统。

2、各子系统通过Http或其它协议与认证系统通信,完成用户认证。

3、用户身份信息存储在Redis集群。

Java中有很多用户认证的框架都可以实现单点登录:

1、Apache Shiro.

2、CAS

3、Spring security CAS

2.2Oauth2认证

单点登录的特点是:

1、认证系统为独立的系统。

2、各子系统通过Http或其它协议与认证系统通信,完成用户认证。

3、用户身份信息存储在Redis集群。

Java中有很多用户认证的框架都可以实现单点登录: 1、Apache Shiro.

2、CAS

3、Spring security CAS

2.2Oauth2认证

2.2.1Oauth2认证流程

第三方认证技能方案最紧张是办理认证协议的通用标准 问题,由于要实现 跨系统认证,各系统之间要遵照一定的接口协议。

OAUTH协议为用户资源的授权供应了一个安全的、开放而又大略单纯的标准。
同时,任何第三方都可以利用OAUTH认证做事,任何做事供应商都可以实现自身的OAUTH认证做事,因而OAUTH是开放的。
业界供应了OAUTH的多种实现如PHP、JavaScript,Java,Ruby等各种措辞开拓包,大大节约了程序员的韶光,因而OAUTH是大略单纯的。
互联网很多做事如Open API,很多大公司如Google,Yahoo,Microsoft等都供应了OAUTH认证做事,这些都足以解释OAUTH标准逐渐成为开放资源授权的标准。

Oauth协议目前发展到2.0版本,1.0版本过于繁芜,2.0版本已得到广泛运用。
参考:https://baike.baidu.com/item/oAuth/7153134?fr=aladdin

Oauth协议:https://tools.ietf.org/html/rfc6749

下边剖析一个Oauth2认证的例子,黑马程序员网站利用微信认证的过程:

第三方认证技能方案最紧张是办理认证协议的通用标准 问题,由于要实现 跨系统认证,各系统之间要遵照一定的接口协议。

OAUTH协议为用户资源的授权供应了一个安全的、开放而又大略单纯的标准。
同时,任何第三方都可以利用OAUTH认证做事,任何做事供应商都可以实现自身的OAUTH认证做事,因而OAUTH是开放的。
业界供应了OAUTH的多种实现如PHP、JavaScript,Java,Ruby等各种措辞开拓包,大大节约了程序员的韶光,因而OAUTH是大略单纯的。
互联网很多做事如Open API,很多大公司如Google,Yahoo,Microsoft等都供应了OAUTH认证做事,这些都足以解释OAUTH标准逐渐成为开放资源授权的标准。

Oauth协议目前发展到2.0版本,1.0版本过于繁芜,2.0版本已得到广泛运用。
参考:https://baike.baidu.com/item/oAuth/7153134?fr=aladdin

Oauth协议:https://tools.ietf.org/html/rfc6749

下边剖析一个Oauth2认证的例子,黑马程序员网站利用微信认证的过程::

1、客户端要求第三方授权

用户进入黑马程序的登录页面,点击微信的图标以微信账号登录系统,用户是自己在微信里信息的资源拥有者。

点击“微信”涌现一个二维码,此时用户扫描二维码,开始给黑马程序员授权。

2、资源拥有者赞许给客户端授权

资源拥有者扫描二维码表示资源拥有者赞许给客户端授权,微信会对资源拥有者的身份进行验证, 验证通过后,微信会讯问用户是否给授权黑马程序员访问自己的微信数据,用户点击“确认登录”表示赞许授权,微信认证做事器会 颁发一个授权码,并重定向到黑马程序员的网站。

3、客户端获取到授权码,要求认证做事器申请令牌

此过程用户看不到,客户端运用程序要求认证做事器,要求携带授权码。

4、认证做事器向客户端相应令牌

认证做事器验证了客户端要求的授权码,如果合法则给客户端颁发令牌,令牌是客户端访问资源的通畅证。
此交互过程用户看不到,当客户端拿到令牌后,用户在黑马程序员看到已经登录成功。

5、客户端要求资源做事器的资源

客户端携带令牌访问资源做事器的资源。

黑马程序员网站携带令牌要求访问微信服务器获取用户的基本信息。

6、资源做事器返回受保护资源

资源做事器校验令牌的合法性,如果合法则向用户相应资源信息内容。

把稳:资源做事器和认证做事器可以是一个做事也可以分开的做事,如果是分开的做事资源做事器常日要要求认证 做事器来校验令牌的合法性。

Oauth2.0认证流程如下:

引自Oauth2.0协议rfc6749 https://tools.ietf.org/html/rfc6749

Oauth2包括以下角色:

1、客户端

本身不存储资源,须要通过资源拥有者的授权去要求资源做事器的资源,比如:学成在线Android客户端、学成在线Web客户端(浏览器端)、微信客户端等。

2、资源拥有者

常日为用户,也可以是运用程序,即该资源的拥有者。

3、授权做事器(也称认证做事器)

用来对资源拥有的身份进行认证、对访问资源进行授权。
客户端要想访问资源须要通过认证做事器由资源拥有者授 权后方可访问。

4、资源做事器

存储资源的做事器,比如,学成网用户管理做事器存储了学成网的用户信息,学成网学习做事器存储了学生的学习 信息,微信的资源做事存储了微信的用户信息等。
客户端终极访问资源做事器获取资源信息。

2.2.2Oauth2在本项目的运用

Oauth2是一个标准的开放的授权协议,运用程序可以根据自己的哀求去利用Oauth2,本项目利用Oauth2实现如下目标:

1、学成在线访问第三方系统的资源

2、外部系统访问学成在线的资源

3、学成在线前端(客户端) 访问学成在线微做事的资源。

4、学成在线微做事之间访问资源,例如:微做事A访问微做事B的资源,B访问A的资源。

2.3Spring security Oauth2认证办理方案

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

1、用户要求认证做事完成认证。

2、认证做事下发用户身份令牌,拥有身份令牌表示身份合法。

3、用户携带令牌要求资源做事,要求资源做事必先经由网关。

4、网关校验用户身份令牌的合法,不合法表示用户没有登录,如果合法则放行连续访问。

5、资源做事获取令牌,根据令牌完成授权。

6、资源做事完成授权则相应资源信

3Spring Security Oauth2研究

3.1目标

本项目认证做事基于Spring Security Oauth2进行构建,并在其根本上作了一些扩展,采取JWT令牌机制,并自定义了用户身份信息的内容。
本教程的紧张目标是学习在项目中集成Spring Security Oauth2的方法和流程,通过spring Security Oauth2的研究须要达到以下目标:

1、理解Oauth2的授权码认证流程及密码认证的流程。

2、理解spring Security Oauth2的事情流程。

3、节制资源做事集成spring Security框架完成Oauth2认证的流程。

3.2搭建认证做事器息。

3.2.1导入根本工程

导入“资料”目录下的 xc-service-ucenter-auth工程,该工程是基于Spring Security Oauth2的一个二次封装的工程,导入此工程研究Oauth2认证流程。

3.2.2创建数据库

导入资料目录下的 xc_user.sql,创建用户数据库

以“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

3.3Oauth2授权码模式

3.3.1Oauth2授权模式

Oauth2有以下授权模式:

授权码模式(Authorization Code)

隐式授权模式(Implicit)

密码模式(Resource Owner Password Credentials)

客户端模式(Client Credentials)

个中授权码模式和密码模式运用较多,本小节先容授权码模式。

3.3.2授权码授权流程

上边例举的黑马程序员网站利用微信认证的过程便是授权码模式,流程如下:

1、客户端要求第三方授权 2、用户(资源拥有者)赞许给客户端授权 3、客户端获取到授权码,要求认证做事器申请令牌 4、认证做事器向客户端相应令牌 5、客户端要求资源做事器的资源,资源做事校验令牌合法性,完成授权

6、资源做事器返回受保护资源

3.3.2申请授权码

要求认证做事获取授权码:

Get要求:

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即可认证通过。

点击“赞许”。

接下来返回授权码:

认证做事携带授权码跳转redirect_uri

3.3.3申请令牌

拿到授权码后,申请令牌。

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和客户端密码会匹配数据库oauth_client_details表中的客户端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:范围,与定义的客户端范围同等。

3.3.4资源做事授权

3.3.4.1资源做事授权流程

资源做事拥有要访问的受保护资源,客户端携带令牌访问资源做事,如果令牌合法则可成功访问资源做事中的资 源,如下图:

上图的业务流程如下:

1、客户端要求认证做事申请令牌

2、认证做事天生令牌

认证做事采取非对称加密算法,利用私钥天生令牌。

3、客户端携带令牌访问资源做事

客户端在Http header 中添加: Authorization:Bearer 令牌。

4、资源做事要求认证做事校验令牌的有效性

资源做事吸收到令牌,利用公钥校验令牌的合法性。

5、令牌有效,资源做事向客户端相应资源信息

3.3.4.2资源做事授权配置

基本上所有微做事都是资源做事,这里我们在课程管理做事上配置授权掌握,当配置了授权掌握后如要访问课程信 息则必须供应令牌。

1、配置公钥

认证做事天生令牌采取非对称加密算法,认证做事采取私钥加密天生令牌,对外向资源做事供应公钥,资源做事使 用公钥 来校验令牌的合法性。

将公钥拷贝到 publickey.txt文件中,将此文件拷贝到资源做事工程的classpath下

2、添加依赖

2、添加依赖

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

4、在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();

}

}

3.3.4.3资源做事授权测试

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

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

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

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

要求时携带令牌:

在http header中添加 Authorization: Bearer 令牌

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

3.3.4.4办理swagger-ui无法访问

当课程管理加了授权之后再访问swagger-ui则报错:

修正授权配置类ResourceServerConfig的configure方法: 针对swagger-ui的要求路径进行放行:

//Http安全配置,对每个到达系统的http要求链接进行校验@Overridepublic 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,但是无法进行单元测试,除非去掉认证的配置或在上边配置中添加所有要求均放行(\公众/\"大众)。

3.4Oauth2密码模式授权

密码模式(Resource Owner Password Credentials)与授权码模式的差异是申请令牌不再利用授权码,而是直接通过用户名和密码即可申请令牌。

测试如下:

Post要求:http://localhost:40400/auth/oauth/token

参数:

grant_type:密码模式授权填写password username:账号

password:密码

并且此链接须要利用 http Basic认证。

上边参数利用x-www-form-urlencoded办法传输,利用postman测试如下:

把稳:当令牌没有过期时同一个用户再次申请令牌则不再颁发新令牌。

3.5校验令牌

Spring Security Oauth2供应校验令牌的端点,如下:

Get: http://localhost:40400/auth/oauth/check_token?token=

参数:

token:令牌

利用postman测试如下:

结果如下:

{\公众companyId\公众: null,\公众userpic\"大众: null, \"大众user_name\公众: \公众mrt\"大众, \公众scope\"大众: [\"大众app\公众],\"大众name\"大众: null,\"大众utype\公众: null,\"大众id\"大众: null,\公众exp\"大众: 1531254828,\"大众jti\"大众: \"大众6a00f227‐4c30‐47dc‐a959‐c0c147806462\"大众, \"大众client_id\公众: \"大众XcWebApp\"大众}

exp:过期韶光,long类型,间隔1970年的秒数(new Date().getTime()可得到当前韶光间隔1970年的毫秒数)。
user_name: 用户名

client_id:客户端Id,在oauth_client_details中配置scope:客户端范围,在oauth_client_details表中配置jti:与令牌对应的唯一标识

companyId、userpic、name、utype、id:这些字段是本认证做事在Spring Security根本上扩展的用户身份信息

3.5刷新令牌

刷新令牌是当令牌快过期时重新天生一个令牌,它于授权码授权和密码授权天生令牌不同,刷新令牌不须要授权码 也不须要账号和密码,只须要一个刷新令牌、客户端id和客户端密码。

测 试 如 下 : Post:http://localhost:40400/auth/oauth/token 参数:

grant_type: 固定为 refresh_token

refresh_token:刷新令牌(把稳不是access_token,而是refresh_token)

刷新令牌成功,会重新天生新的访问令牌和刷新令牌,令牌的有效期也比旧令牌长。
刷新令牌常日是在令牌快过期时进行刷新。

3.6JWT研究

3.6.1JWT先容

在先容JWT之前先看一下传统校验令牌的方法,如下图:

问题:

传统授权方法的问题是用户每次要求资源做事,资源做事都须要携带令牌访问认证做事去校验令牌的合法性,并根 据令牌获取用户的干系信息,性能低下。

办理:

利用JWT的思路是,用户认证通过会得到一个JWT令牌,JWT令牌中已经包括了用户干系的信息,客户端只须要携带JWT访问资源做事,资源做事根据事先约定的算法自行完成令牌校验,无需每次都要求认证做事完成授权。

JWT令牌授权过程如下图:

什么是JWT?

JSON Web Token(JWT)是一个开放的行业标准(RFC 7519),它定义了一种简介的、自包含的协议格式,用于在通信双方通报json工具,通报的信息经由数字署名可以被验证和信赖。
JWT可以利用HMAC算法或利用RSA的公钥/私钥对来署名,防止被修改。

官网:https://jwt.io/

标准:https://tools.ietf.org/html/rfc7519

JWT令牌的优点:

1、jwt基于json,非常方便解析。

2、可以在令牌中自定义丰富的内容,易扩展。

3、通过非对称加密算法及数字署名技能,JWT防止修改,安全性高。

4、资源做事利用JWT可不依赖认证做事即可完成授权。
缺陷:

1、JWT令牌较长,占存储空间比较大。

3.6.1.1令牌构造

通过学习JWT令牌构造为自定义jwt令牌打好根本。

JWT令牌由三部分组成,每部分中间利用点(.)分隔,比如:xxxxx.yyyyy.zzzzz Header

头部包括令牌的类型(即JWT)及利用的哈希算法(如HMAC SHA256或RSA)

一个例子如下:

下边是Header部分的内容

{\公众alg\公众: \"大众HS256\公众,\"大众typ\"大众: \"大众JWT\"大众}

将上边的内容利用Base64Url编码,得到一个字符串便是JWT令牌的第一部分。

Payload

第二部分是负载,内容也是一个json工具,它是存放有效信息的地方,它可以存放jwt供应的现成字段,比如:iss(签发者),exp(过期韶光戳), sub(面向的用户)等,也可自定义字段。

此部分不建议存放敏感信息,由于此部分可以解码还原原始内容。

末了将第二部分负载利用Base64Url编码,得到一个字符串便是JWT令牌的第二部分。
一个例子:

{\公众sub\"大众: \公众1234567890\"大众,\"大众name\公众: \"大众456\"大众, \"大众admin\"大众: true}

Signature

第三部分是署名,此部分用于防止jwt内容被修改。

这个部分利用base64url将前两部分进行编码,编码后利用点(.)连接组成字符串,末了利用header中声明署名算法进行署名。

一个例子:

HMACSHA256(base64UrlEncode(header) + \公众.\"大众 + base64UrlEncode(payload), secret)

base64UrlEncode(header):jwt令牌的第一部分。
base64UrlEncode(payload):jwt令牌的第二部分。
secret:署名所利用的密钥。

3.6.3JWT入门

Spring Security 供应对JWT的支持,本节我们利用Spring Security 供应的JwtHelper来创建JWT令牌,校验JWT令牌等操作。

3.6.3.1天生私钥和公钥JWT

令牌天生采取非对称加密算法

1、天生密钥证书

下边命令天生密钥证书,采取RSA 算法每个证书包含公钥和私钥

keytool -genkeypair -alias xckey -keyalg RSA -keypass xuecheng -keystore xc.keystore -storepass xuechengkeystore

Keytool 是一个java供应的证书管理工具

-alias:密钥的别名

-keyalg:利用的hash算法

-keypass:密钥的访问密码

-keystore:密钥库文件名,xc.keystore保存了天生的证书

-storepass:密钥库的访问密码

查询证书信息:

keytool -list -keystore xc.keystore

删除别名

keytool -delete -alias xckey -keystore xc.keystore

2、导出公钥

openssl是一个加解密工具包,这里利用openssl来导出公钥信息。

安装 openssl:http://slproweb.com/products/Win32OpenSSL.html

安装资料目录下的Win64OpenSSL-1_1_0g.exe

配置openssl的path环境变量,本教程配置在D:\OpenSSL-Win64\bin cmd进入xc.keystore文件所在目录实行如下命令:

keytool ‐list ‐rfc ‐‐keystore xc.keystore | openssl x509 ‐inform pem ‐pubkey

输入密钥库密码:

下边这一段便是公钥内容:

-----BEGIN PUBLIC KEY-----

MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAijyxMdq4S6L1Af1rtB8SjCZHNgsQG8JTfGy55eYvzG0B

/E4AudR2prSRBvF7NYPL47scRCNPgLnvbQczBHbBug6uOr78qnWsYxHlW6Aa5dI5NsmOD4DLtSw8eX0hFyK5F j6ScYOSFBz9cd1nNTvx2+oIv0lJDcpQdQhsfgsEr1ntvWterZt/8r7xNN83gHYuZ6TM5MYvjQNBc5qC7Krs9wM7U oQuL+s0X6RlOib7/mcLn/lFLsLDdYQAZkSDx/6+t+1oHdMarChIPYT1sx9Dwj2j2mvFNDTKKKKAq0cv14Vrhz67Vj mz2yMJePDqUi0JYS2r0iIo7n8vN7s83v5uOQIDAQAB-----END PUBLIC KEY-----

将上边的公钥拷贝到文本文件中,合并为一行。

3.6.3.2天生jwt令牌

在认证工程创建测试类,测试jwt令牌的天生与验证。

//天生一个jwt令牌@Testpublic void testCreateJwt(){//证书文件String key_location = \"大众xc.keystore\公众;//密钥库密码String keystore_password = \"大众xuechengkeystore\"大众;//访问证书路径ClassPathResource resource = new ClassPathResource(key_location);//密钥工厂KeyStoreKeyFactory keyStoreKeyFactory = new KeyStoreKeyFactory(resource, keystore_password.toCharArray());//密钥的密码,此密码和别名要匹配String keypassword = \"大众xuecheng\"大众;//密钥别名String alias = \"大众xckey\公众;//密钥对(密钥和公钥)KeyPair keyPair = keyStoreKeyFactory.getKeyPair(alias,keypassword.toCharArray());//私钥RSAPrivateKey aPrivate = (RSAPrivateKey) keyPair.getPrivate();//定义payload信息Map<String, Object> tokenMap = new HashMap<>(); tokenMap.put(\公众id\"大众, \"大众123\公众);tokenMap.put(\"大众name\"大众, \"大众mrt\"大众);tokenMap.put(\公众roles\"大众, \"大众r01,r02\"大众);tokenMap.put(\公众ext\"大众, \公众1\公众);//天生jwt令牌Jwt jwt = JwtHelper.encode(JSON.toJSONString(tokenMap), new RsaSigner(aPrivate));//取出jwt令牌String token = jwt.getEncoded();System.out.println(\公众token=\"大众+token);}

3.6.3.3验证jwt令牌

//资源做事利用公钥验证jwt的合法性,并对jwt解码@Test

public void testVerify(){

//jwt令牌String token

=\公众eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHQiOiIxIiwicm9sZXMiOiJyMDEscjAyIiwibmFtZSI6Im1ydCIsI mlkIjoiMTIzIn0.KK7_67N5d1Dthd1PgDHMsbi0UlmjGRcm_XJUUwseJ2eZyJJWoPP2IcEZgAU3tUaaKEHUf9wSRwaDgwhrw fyIcSHbs8oy3zOQEL8j5AOjzBBs7vnRmB7DbSaQD7eJiQVJOXO1QpdmEFgjhc_IBCVTJCVWgZw60IEW1_Lg5tqaLvCiIl26K 48pJB5f‐le2zgYMzqR1L2LyTFkq39rG57VOqqSCi3dapsZQd4ctq95SJCXgGdrUDWtD52rp5o6_0uq‐ mrbRdRxkrQfsa1j8C5IW2‐T4eUmiN3f9wF9JxUK1 XC1OQkOn‐ZTBCdqwWIygDFbU7sf6KzfHJTm5vfjp6NIA\"大众;

//公钥

String publickey = \"大众‐‐‐‐‐BEGIN PUBLIC KEY‐‐‐‐‐ MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAijyxMdq4S6L1Af1rtB8SjCZHNgsQG8JTfGy55eYvzG0B/E4AudR2 prSRBvF7NYPL47scRCNPgLnvbQczBHbBug6uOr78qnWsYxHlW6Aa5dI5NsmOD4DLtSw8eX0hFyK5Fj6ScYOSFBz9cd1nNTvx 2+oIv0lJDcpQdQhsfgsEr1ntvWterZt/8r7xNN83gHYuZ6TM5MYvjQNBc5qC7Krs9wM7UoQuL+s0X6RlOib7/mcLn/lFLsLD dYQAZkSDx/6+t+1oHdMarChIPYT1sx9Dwj2j2mvFNDTKKKKAq0cv14Vrhz67Vjmz2yMJePDqUi0JYS2r0iIo7n8vN7s83v5u OQIDAQAB‐‐‐‐‐END PUBLIC KEY‐‐‐‐‐\"大众;

//校验jwt

Jwt jwt = JwtHelper.decodeAndVerify(token, new RsaVerifier(publickey));

//获取jwt原始内容

String claims = jwt.getClaims();

//jwt令牌

String encoded = jwt.getEncoded(); System.out.println(encoded);

}

4认证接口开拓

4.1需求剖析

用户登录的流程图如下:

实行流程:

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,由客户端要求做事端获取并在客户端存 储。

4.2Redis配置

4.2.1安装Redis

1、安装Redis做事

下载Windows版本的redis:https://github.com/MicrosoftArchive/redis/tags 下载Redis-x64-3.2.100版本,解压Redis-x64-3.2.100.zip

进入cmd命令行,进入Redis-x64-3.2.100目录。

运行:

redis‐server redis.windows.conf

涌现 下图解释 redis启动成功:

注册为做事:

redis‐server ‐‐service‐install redis.windows‐service.conf ‐‐loglevel verbose

刷新做事,会看到多了一个redis做事。

常用的redis做事命令如下: 进入redis安装目录:

卸载做事:redis-server.exe --service-uninstall

开启做事:redis-server.exe --service-start

停滞做事:redis-server.exe --service-stop

2、redis-desktop-manager

下载windows版本的redis客户端:https://redisdesktop.com/download 下载redis-desktop-manager-0.9.2.806.exe

安装后启动redis客户端: 配置redis链接:

连接成功:

4.2.2redis连接配置

在认证做事的application.yml文件中添加如下配置:

spring:application:name: xc‐service‐ucenter‐auth redis:host: ${REDIS_HOST:127.0.0.1} port: ${REDIS_PORT:6379}timeout: 5000 #连接超时 毫秒jedis:pool:maxActive: 3maxIdle: 3minIdle: 1maxWait: ‐1 #连接池最大等行韶光 ‐1没有限定

4.2.3测试

@SpringBootTest @RunWith(SpringRunner.class) public class RedisTest {@Autowiredprivate StringRedisTemplate stringRedisTemplate; @Testpublic void testRedis(){//定义keyString key = \"大众user_token:9734b68f‐cf5e‐456f‐9bd6‐df578c711390\"大众;//定义MapMap<String,String> mapValue = new HashMap<>(); mapValue.put(\"大众id\公众,\"大众101\公众); mapValue.put(\公众username\"大众,\"大众itcast\公众);String value = JSON.toJSONString(mapValue);// 向 redis 中 存 储 字 符 串 stringRedisTemplate.boundValueOps(key).set(value,60, TimeUnit.SECONDS);//读取过期韶光,已过期返回‐2Long expire = stringRedisTemplate.getExpire(key);//根据key获取valueString s = stringRedisTemplate.opsForValue().get(key); System.out.println(s);}}

4.3认证做事

4.3.1需求剖析

认证做事须要实现的功能如下:

1、登录接口

前端post提交账号、密码等,用户身份校验通过,天生令牌,并将令牌存储到redis。
将令牌写入cookie。

2、退出接口

校验当前用户的身份为合法并且为已登录状态。
将令牌从redis删除。

删除cookie中的令牌。
业务流程如下:

4.3.2Api接口

@Api(value = \"大众用户认证\"大众,description = \"大众用户认证接口\公众) public interface AuthControllerApi {@ApiOperation(\公众登录\公众)public LoginResult login(LoginRequest loginRequest);@ApiOperation(\"大众退出\"大众)public ResponseResult logout();}

4.3.3配置参数

在application.yml中配置参数

auth:tokenValiditySeconds: 1200 #token存储到redis的过期韶光clientId: XcWebAppclientSecret: XcWebApp cookieDomain: localhost cookieMaxAge: ‐1

4.3.4申请令牌测试

为了不毁坏Spring Security的代码,我们在Service方法中通过RestTemplate要求Spring Security所暴露的申请令牌接口来申请令牌,下边是测试代码:

@SpringBootTest @RunWith(SpringRunner.class) public class TestClient {@AutowiredLoadBalancerClient loadBalancerClient;@AutowiredRestTemplate restTemplate;@Testpublic void testClient(){//采取客户端负载均衡,从eureka获取认证做事的ip 和端口ServiceInstance serviceInstance = loadBalancerClient.choose(XcServiceList.XC_SERVICE_UCENTER_AUTH);URI uri = serviceInstance.getUri();String authUrl = uri+\公众/auth/oauth/token\"大众;@SpringBootTest @RunWith(SpringRunner.class) public class TestClient {@AutowiredLoadBalancerClient loadBalancerClient;@AutowiredRestTemplate restTemplate;@Testpublic void testClient(){//采取客户端负载均衡,从eureka获取认证做事的ip 和端口ServiceInstance serviceInstance = loadBalancerClient.choose(XcServiceList.XC_SERVICE_UCENTER_AUTH);URI uri = serviceInstance.getUri();String authUrl = uri+\"大众/auth/oauth/token\"大众;

4.3.4Dao

暂时利用静态数据,待用户登录调通再连接数据库校验用户信息。

4.3.5Service

调用认证做事申请令牌,并将令牌存储到 redis。
1、AuthToken

创建 AuthToken模型类,存储申请的令牌,包括身份令牌、刷新令牌、jwt令牌身份令牌:用于校验用户是否认证

刷新令牌:jwt令牌快过期时实行刷新令牌

jwt令牌:用于授权

@Data @ToString@NoArgsConstructor public class AuthToken {String access_token;//身份tokenString refresh_token;//刷新token String jwt_token;//jwt令牌}

申请令牌的service方法如下:

@Servicepublic class AuthService {private static final Logger LOGGER = LoggerFactory.getLogger(AuthService.class); @Value(\公众${auth.tokenValiditySeconds}\"大众)int tokenValiditySeconds;@AutowiredRestTemplate restTemplate; @AutowiredLoadBalancerClient loadBalancerClient; @AutowiredStringRedisTemplate stringRedisTemplate;//认证方法public AuthToken login(String username,String password,String clientId,String clientSecret){//申请令牌AuthToken authToken = applyToken(username,password,clientId, clientSecret); if(authToken == null){ExceptionCast.cast(AuthCode.AUTH_LOGIN_APPLYTOKEN_FAIL);}//将 token存储到redisString access_token = authToken.getAccess_token(); String content = JSON.toJSONString(authToken);boolean saveTokenResult = saveToken(access_token, content, tokenValiditySeconds);if(!saveTokenResult){ExceptionCast.cast(AuthCode.AUTH_LOGIN_TOKEN_SAVEFAIL);}return authToken;}//存储令牌到redisprivate boolean saveToken(String access_token,String content,long ttl){//令牌名称String name = \"大众user_token:\"大众 + access_token;//保存到令牌到redisstringRedisTemplate.boundValueOps(name).set(content,ttl, TimeUnit.SECONDS);//获取过期韶光Long expire = stringRedisTemplate.getExpire(name); return expire>0;}//认证方法private AuthToken applyToken(String username,String password,String clientId,String clientSecret){//选中认证做事的地址ServiceInstance serviceInstance = loadBalancerClient.choose(XcServiceList.XC_SERVICE_UCENTER_AUTH);if (serviceInstance == null) { LOGGER.error(\公众choose an auth instance fail\"大众);ExceptionCast.cast(AuthCode.AUTH_LOGIN_AUTHSERVER_NOTFOUND);}//获取令牌的urlString path = serviceInstance.getUri().toString()+\公众/auth/oauth/token\"大众;//定义bodyMultiValueMap<String,String> formData = new LinkedMultiValueMap<>();//授权办法formData.add(\"大众grant_type\"大众, \公众password\"大众);//账号formData.add(\"大众username\"大众,username);//密码formData.add(\"大众password\"大众, password);//定义头MultiValueMap<String,String> header = new LinkedMultiValueMap<>(); header.add(\"大众Authorization\"大众, httpbasic(clientId,clientSecret));//指定 restTemplate当碰着400或401相应时候也不要抛出非常,也要正常返回值restTemplate.setErrorHandler(new DefaultResponseErrorHandler(){@Overridepublic void handleError(ClientHttpResponse response) throws IOException {//当相应的值为400或401时候也要正常相应,不要抛出非常if(response.getRawStatusCode()!=400 && response.getRawStatusCode()!=401){super.handleError(response);}}});Map map = null; try {//http要求spring security的申请令牌接口ResponseEntity<Map> mapResponseEntity = restTemplate.exchange(path, HttpMethod.POST,new HttpEntity<MultiValueMap<String, String>>(formData, header), Map.class); map = mapResponseEntity.getBody();} catch (RestClientException e) { e.printStackTrace();LOGGER.error(\公众request oauth_token_password error: {}\"大众,e.getMessage()); e.printStackTrace(); ExceptionCast.cast(AuthCode.AUTH_LOGIN_APPLYTOKEN_FAIL);}if(map == null ||map.get(\"大众access_token\"大众) == null || map.get(\"大众refresh_token\"大众) == null ||map.get(\公众jti\公众) == null){//jti是jwt令牌的唯一标识作为用户身份令牌ExceptionCast.cast(AuthCode.AUTH_LOGIN_APPLYTOKEN_FAIL);}AuthToken authToken = new AuthToken();//访问令牌(jwt)String jwt_token = (String) map.get(\"大众access_token\"大众);//刷新令牌(jwt)String refresh_token = (String) map.get(\"大众refresh_token\"大众);//jti,作为用户的身份标识String access_token = (String) map.get(\公众jti\"大众); authToken.setJwt_token(jwt_token); authToken.setAccess_token(access_token); authToken.setRefresh_token(refresh_token); return authToken;}//获取httpbasic认证串private String httpbasic(String clientId,String clientSecret){//将客户端id和客户端密码拼接,按“客户端id:客户端密码” String string = clientId+\"大众:\公众+clientSecret;//进行base64编码byte[] encode = Base64.encode(string.getBytes()); return \"大众Basic \公众+new String(encode);}}

4.3.6Controller

AuthController代码如下:

@RestControllerpublic class AuthController implements AuthControllerApi { @Value(\"大众${auth.clientId}\公众)String clientId; @Value(\公众${auth.clientSecret}\"大众)String clientSecret;@Value(\公众${auth.cookieDomain}\公众) String cookieDomain; @Value(\公众${auth.cookieMaxAge}\"大众) int cookieMaxAge;@Value(\"大众${auth.tokenValiditySeconds}\公众) int tokenValiditySeconds;@AutowiredAuthService authService;@Override @PostMapping(\公众/userlogin\"大众)public LoginResult login(LoginRequest loginRequest) {//校验账号是否输入if(loginRequest == null || StringUtils.isEmpty(loginRequest.getUsername())){ ExceptionCast.cast(AuthCode.AUTH_USERNAME_NONE);}//校验密码是否输入if(StringUtils.isEmpty(loginRequest.getPassword())){ExceptionCast.cast(AuthCode.AUTH_PASSWORD_NONE);}AuthToken authToken = authService.login(loginRequest.getUsername(), loginRequest.getPassword(), clientId, clientSecret);//将令牌写入cookie//访问tokenString access_token = authToken.getAccess_token();//将访问令牌存储到cookie saveCookie(access_token);return new LoginResult(CommonCode.SUCCESS,access_token);}//将令牌保存到cookieprivate void saveCookie(String token){HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();//添加cookie 认证令牌,末了一个参数设置为false,表示许可浏览器获取CookieUtil.addCookie(response, cookieDomain, \"大众/\公众, \"大众uid\"大众, token, cookieMaxAge, false);}@Override @PostMapping(\公众/userlogout\公众) public ResponseResult logout() {return null;}}

4.3.7登录url放行

认证做事默认都要校验用户的身份信息,这里须要将登录url放行。

在WebSecurityConfig类中重写 configure(WebSecurity web)方法,如下:

@Overridepublic void configure(WebSecurity web) throws Exception { web.ignoring().antMatchers(\"大众/userlogin\"大众);}

4.3.8测试认证接口

利用postman测试:

Post要求:http://localhost:40400/auth/userlogin

4.3.9测试写入Cookie

cookie终极会写到xuecheng.com域名下,可通过nginx代理进行认证,测试cookie是否写成功。
1、配置nginx代理

在ucenter.xuecheng.com下配置代理路径

#认证location ^~ /openapi/auth/ {proxy_pass http://auth_server_pool/auth/;}

添加:

#认证做事upstream auth_server_pool{server 127.0.0.1:40400 weight=10;}

2、要求:http://ucenter.xuecheng.com/openapi/auth/userlogin

不雅观察cookie写入结果

标签:

相关文章

百知网站,您的知识宝藏,一站式学习平台

人们获取知识的渠道日益丰富。如何高效地获取所需知识,成为了许多人关注的焦点。百知网站,作为一款集知识学习、资源共享、互动交流于一体...

SEO优化 2025-03-23 阅读0 评论0

糖果的,甜蜜诱惑背后的故事与科学

糖果,作为世界上最古老的食品之一,早已融入了人们的生活。从古代的蜜饯、果脯,到现代的巧克力、软糖,糖果的种类繁多,口味各异。糖果究...

SEO优化 2025-03-23 阅读0 评论0

筑牢网络安全防线,维护国家网站稳定运行

我国网站数量逐年攀升,已成为全球互联网大国。网络安全形势日益严峻,国家网站作为国家形象的重要窗口,其稳定运行关乎国家安全和社会稳定...

SEO优化 2025-03-23 阅读0 评论0

细河网站,助力企业腾飞的数字化桥梁

越来越多的企业开始重视网络营销,借助网络平台拓展市场,提升品牌知名度。细河网站作为一家专业的网络营销服务提供商,凭借其卓越的技术实...

SEO优化 2025-03-23 阅读0 评论0

童装网站,为宝宝打造时尚舒适的童年衣橱

人们对儿童的教育、生活和审美需求日益提高。童装作为儿童生活中的重要组成部分,不仅关系到孩子的健康成长,更体现着家庭的品味。童装行业...

SEO优化 2025-03-23 阅读0 评论0