赞
踩
认证授权过程
在认证和授权的过程中涉及的三方包括:
1、服务提供方,用户使用服务提供方来存储受保护的资源,如照片,视频,联系人列表。
2、用户,存放在服务提供方的受保护的资源的拥有者。
3、客户端,要访问服务提供方资源的第三方应用,通常是网站,如提供照片打印服务的网站。在认证过程之前,客户端要向服务提供者申请客户端标识。
使用OAuth进行认证和授权的过程如下所示:
用户想操作存放在服务提供方的资源。
用户登录客户端向服务提供方请求一个临时令牌。
服务提供方验证客户端的身份后,授予一个临时令牌。
客户端获得临时令牌后,将用户引导至服务提供方的授权页面请求用户授权。在这个过程中将临时令牌和客户端的回调连接发送给服务提供方。
用户在服务提供方的网页上输入用户名和密码,然后授权该客户端访问所请求的资源。
授权成功后,服务提供方引导用户返回客户端的网页。
客户端根据临时令牌从服务提供方那里获取访问令牌。
服务提供方根据临时令牌和用户的授权情况授予客户端访问令牌。
客户端使用获取的访问令牌访问存放在服务提供方上的受保护的资源。
项目结构
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-web</artifactId>
- </dependency>
-
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-security</artifactId>
- </dependency>
-
- <!-- OAuth2.0依赖,不再内置了,所以得我们自己指定一下版本 -->
- <dependency>
- <groupId>org.springframework.cloud</groupId>
- <artifactId>spring-cloud-starter-oauth2</artifactId>
- <version>2.2.5.RELEASE</version>
- </dependency>
- package com.minos.config;
-
- 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 javax.annotation.Resource;
-
- @EnableAuthorizationServer //开启验证服务器
- @Configuration
- public class OAuth2Configuration extends AuthorizationServerConfigurerAdapter {
-
- @Resource
- private AuthenticationManager manager;
- @Resource
- UserDetailsService service;
-
-
- private final BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
-
- /**
- * 这个方法是对客户端进行配置,一个验证服务器可以预设很多个客户端,
- * 之后这些指定的客户端就可以按照下面指定的方式进行验证
- * @param clients 客户端配置工具
- */
- @Override
- public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
- clients
- .inMemory() //这里我们直接硬编码创建,当然也可以像Security那样自定义或是使用JDBC从数据库读取
- .withClient("web") //客户端名称,随便起就行
- .secret(encoder.encode("654321")) //只与客户端分享的secret,随便写,但是注意要加密
- .autoApprove(false) //自动审批,这里关闭,要的就是一会体验那种感觉
- .scopes("book", "user", "borrow") //授权范围,这里我们使用全部all
- .redirectUris("http://localhost:8201/login") //可以写多个,当有多个时需要在验证请求中指定使用哪个地址进行回调
- .authorizedGrantTypes("client_credentials", "password", "implicit", "authorization_code", "refresh_token");
- //授权模式,一共支持5种,除了之前我们介绍的四种之外,还有一个刷新Token的模式
- //这里我们直接把五种都写上,方便一会实验,当然各位也可以单独只写一种一个一个进行测试
- //现在我们指定的客户端就支持这五种类型的授权方式了
- }
-
- @Override
- public void configure(AuthorizationServerSecurityConfigurer security) {
- security
- .passwordEncoder(encoder) //编码器设定为BCryptPasswordEncoder
- .allowFormAuthenticationForClients() //允许客户端使用表单验证,一会我们POST请求中会携带表单信息
- .checkTokenAccess("permitAll()"); //允许所有的Token查询请求
- }
-
- @Override
- public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
- endpoints
- .authenticationManager(manager);
- //由于SpringSecurity新版本的一些底层改动,这里需要配置一下authenticationManager,才能正常使用password模式
- endpoints
- .userDetailsService(service);
- }
- }
- package com.minos.config;
-
- import org.springframework.context.annotation.Bean;
- import org.springframework.context.annotation.Configuration;
- import org.springframework.security.authentication.AuthenticationManager;
- import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
- import org.springframework.security.config.annotation.web.builders.HttpSecurity;
- import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
- import org.springframework.security.core.userdetails.UserDetailsService;
- import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
-
- @Configuration
- public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
-
- @Override
- protected void configure(HttpSecurity http) throws Exception {
- http
- .authorizeRequests()
- .anyRequest().authenticated() //
- .and()
- .formLogin().permitAll(); //使用表单登录
- }
-
- @Override
- protected void configure(AuthenticationManagerBuilder auth) throws Exception {
- BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
- auth
- .inMemoryAuthentication() //直接创建一个用户,懒得搞数据库了
- .passwordEncoder(encoder)
- .withUser("test").password(encoder.encode("123456")).roles("USER");
- }
-
- @Bean //这里需要将AuthenticationManager注册为Bean,在OAuth配置中使用
- @Override
- public AuthenticationManager authenticationManagerBean() throws Exception {
- return super.authenticationManagerBean();
- }
- @Bean
- @Override
- public UserDetailsService userDetailsServiceBean() throws Exception {
- return super.userDetailsServiceBean();
- }
- }
- import org.springframework.boot.SpringApplication;
- import org.springframework.boot.autoconfigure.SpringBootApplication;
-
- @SpringBootApplication
- public class AuthApplication {
- public static void main(String[] args) {
- SpringApplication.run(AuthApplication.class,args);
- }
- }
- server:
- port: 8500
- servlet:
- #为了防止一会在服务之间跳转导致Cookie打架(因为所有服务地址都是localhost,都会存JSESSIONID)
- #这里修改一下context-path,这样保存的Cookie会使用指定的路径,就不会和其他服务打架了
- #但是注意之后的请求都得在最前面加上这个路径
- context-path: /sso
- http://localhost:8500/sso/oauth/token
- grant_type:client_credentials
- client_id:web
- client_secret:654321
验证token
http://localhost:8500/sso/oauth/check_token?token=7cd6c753-bd1f-4a41-aa60-372dc43f2a70
- http://localhost:8500/sso/oauth/token
- grant_type:password
- username:test
- password:123456
填写请求参数
设置校验账号密码
浏览器调用
http://localhost:8500/sso/oauth/authorize?client_id=web&response_type=token
服务器根据规则携带token重定向至http://localhost:8201/login
http://localhost:8201/login#access_token=2d81d2ff-898f-4138-bc0b-a46c2c15a13c&token_type=bearer&expires_in=42373&scope=book%20borrow%20user
http://localhost:8500/sso/oauth/authorize?client_id=web&response_type=code
浏览器页面登录
勾选权限
返回code
http://localhost:8201/login?code=4om04n
根据返回code获取token
- http://localhost:8500/sso/oauth/token
- grant_type:authorization_code
- client_id:web
- client_secret:654321
- code:4om04n
- http://localhost:8500/sso/oauth/token
- grant_type:refresh_token
- client_id:web
- client_secret:654321
- refresh_token:b1eda2a0-d1bd-4bd3-9c48-67115e159bf2
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-security</artifactId>
- </dependency>
-
- <dependency>
- <groupId>org.springframework.cloud</groupId>
- <artifactId>spring-cloud-starter-oauth2</artifactId>
- <version>2.2.5.RELEASE</version>
- </dependency>
@EnableOAuth2Sso
- security:
- oauth2:
- client:
- #不多说了
- client-id: web
- client-secret: 654321
- #Token获取地址
- access-token-uri: http://localhost:8500/sso/oauth/token
- #验证页面地址
- user-authorization-uri: http://localhost:8500/sso/oauth/authorize
- resource:
- #Token信息获取和校验地址
- token-info-uri: http://localhost:8500/sso/oauth/check_token
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-security</artifactId>
- </dependency>
-
- <dependency>
- <groupId>org.springframework.cloud</groupId>
- <artifactId>spring-cloud-starter-oauth2</artifactId>
- <version>2.2.5.RELEASE</version>
- </dependency>
@EnableResourceServer
- security:
- oauth2:
- client:
- #不多说了
- client-id: web
- client-secret: 654321
- resource:
- #Token信息获取和校验地址
- token-info-uri: http://localhost:8500/sso/oauth/check_token
- @Configuration
- public class ResourceConfiguration extends ResourceServerConfigurerAdapter { //继承此类进行高度自定义
-
- @Override
- public void configure(HttpSecurity http) throws Exception { //这里也有HttpSecurity对象,方便我们配置SpringSecurity
- http
- .authorizeRequests()
- .anyRequest().access("#oauth2.hasScope('lbwnb')"); //添加自定义规则
- //Token必须要有我们自定义scope授权才可以访问此资源
- }
- }
- @Configuration
- public class WebConfiguration {
-
- @Resource
- OAuth2ClientContext context;
-
- @Bean
- public OAuth2RestTemplate restTemplate(){
- return new OAuth2RestTemplate(new ClientCredentialsResourceDetails(), context);
- }
- }
使用OAuth2RestTemplate进行调用,自动携带token
- @Resource
- OAuth2RestTemplate template;
OpenFeign使用参考。
https://blog.csdn.net/qq_29752857/article/details/129221077
- feign:
- oauth2:
- #开启Oauth支持,这样就会在请求头中携带Token了
- enabled: true
- #同时开启负载均衡支持
- load-balanced: true
服务端配置
- @Bean
- public JwtAccessTokenConverter tokenConverter(){ //Token转换器,将其转换为JWT
- JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
- converter.setSigningKey("lbwnb"); //这个是对称密钥,一会资源服务器那边也要指定为这个
- return converter;
- }
-
- @Bean
- public TokenStore tokenStore(JwtAccessTokenConverter converter){ //Token存储方式现在改为JWT存储
- return new JwtTokenStore(converter); //传入刚刚定义好的转换器
- }
- @Resource
- TokenStore store;
-
- @Resource
- JwtAccessTokenConverter converter;
-
- private AuthorizationServerTokenServices serverTokenServices(){ //这里对AuthorizationServerTokenServices进行一下配置
- DefaultTokenServices services = new DefaultTokenServices();
- services.setSupportRefreshToken(true); //允许Token刷新
- services.setTokenStore(store); //添加刚刚的TokenStore
- services.setTokenEnhancer(converter); //添加Token增强,其实就是JwtAccessTokenConverter,增强是添加一些自定义的数据到JWT中
- return services;
- }
-
- @Override
- public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
- endpoints
- .tokenServices(serverTokenServices()) //设定为刚刚配置好的AuthorizationServerTokenServices
- .userDetailsService(service)
- .authenticationManager(manager);
- }
客户端配置,jwt的密钥和服务端配置一样
- security:
- oauth2:
- resource:
- jwt:
- key-value: lbwnb #注意这里要跟验证服务器的密钥一致,这样算出来的签名才会一致
服务端完整配置
-
-
- 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.token.AuthorizationServerTokenServices;
- 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 javax.annotation.Resource;
-
- @EnableAuthorizationServer //开启验证服务器
- @Configuration
- public class OAuth2Configuration extends AuthorizationServerConfigurerAdapter {
-
- @Resource
- private AuthenticationManager manager;
- @Resource
- UserDetailsService service;
- @Resource
- TokenStore store;
-
- @Resource
- JwtAccessTokenConverter converter;
-
- private AuthorizationServerTokenServices serverTokenServices(){ //这里对AuthorizationServerTokenServices进行一下配置
- DefaultTokenServices services = new DefaultTokenServices();
- services.setSupportRefreshToken(true); //允许Token刷新
- services.setTokenStore(store); //添加刚刚的TokenStore
- services.setTokenEnhancer(converter); //添加Token增强,其实就是JwtAccessTokenConverter,增强是添加一些自定义的数据到JWT中
- return services;
- }
-
- private final BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
-
- /**
- * 这个方法是对客户端进行配置,一个验证服务器可以预设很多个客户端,
- * 之后这些指定的客户端就可以按照下面指定的方式进行验证
- *
- * @param clients 客户端配置工具
- */
- @Override
- public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
- clients
- .inMemory() //这里我们直接硬编码创建,当然也可以像Security那样自定义或是使用JDBC从数据库读取
- .withClient("web") //客户端名称,随便起就行
- .secret(encoder.encode("654321")) //只与客户端分享的secret,随便写,但是注意要加密
- .autoApprove(false) //自动审批,这里关闭,要的就是一会体验那种感觉
- .scopes("book", "user", "borrow") //授权范围,这里我们使用全部all
- .redirectUris("http://localhost:8500/login") //可以写多个,当有多个时需要在验证请求中指定使用哪个地址进行回调
- .authorizedGrantTypes("client_credentials", "password", "implicit", "authorization_code", "refresh_token");
- //授权模式,一共支持5种,除了之前我们介绍的四种之外,还有一个刷新Token的模式
- //这里我们直接把五种都写上,方便一会实验,当然各位也可以单独只写一种一个一个进行测试
- //现在我们指定的客户端就支持这五种类型的授权方式了
- }
-
- @Override
- public void configure(AuthorizationServerSecurityConfigurer security) {
- security
- .passwordEncoder(encoder) //编码器设定为BCryptPasswordEncoder
- .allowFormAuthenticationForClients() //允许客户端使用表单验证,一会我们POST请求中会携带表单信息
- .checkTokenAccess("permitAll()"); //允许所有的Token查询请求
- }
-
- @Override
- public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
- endpoints
- .tokenServices(serverTokenServices()) //设定为刚刚配置好的AuthorizationServerTokenServices
- .authenticationManager(manager);
- //由于SpringSecurity新版本的一些底层改动,这里需要配置一下authenticationManager,才能正常使用password模式
- endpoints
- .userDetailsService(service);
- }
- }
-
-
- import org.springframework.context.annotation.Bean;
- import org.springframework.context.annotation.Configuration;
- import org.springframework.security.authentication.AuthenticationManager;
- import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
- import org.springframework.security.config.annotation.web.builders.HttpSecurity;
- import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
- import org.springframework.security.core.userdetails.UserDetailsService;
- import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
- 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 SecurityConfiguration extends WebSecurityConfigurerAdapter {
-
- @Override
- protected void configure(HttpSecurity http) throws Exception {
- http
- .authorizeRequests()
- .anyRequest().authenticated() //
- .and()
- .formLogin().permitAll(); //使用表单登录
- }
-
- @Override
- protected void configure(AuthenticationManagerBuilder auth) throws Exception {
- BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
- auth
- .inMemoryAuthentication() //直接创建一个用户,懒得搞数据库了
- .passwordEncoder(encoder)
- .withUser("test").password(encoder.encode("123456")).roles("USER");
- }
-
- @Bean //这里需要将AuthenticationManager注册为Bean,在OAuth配置中使用
- @Override
- public AuthenticationManager authenticationManagerBean() throws Exception {
- return super.authenticationManagerBean();
- }
- @Bean
- @Override
- public UserDetailsService userDetailsServiceBean() throws Exception {
- return super.userDetailsServiceBean();
- }
- @Bean
- public JwtAccessTokenConverter tokenConverter(){ //Token转换器,将其转换为JWT
- JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
- converter.setSigningKey("lbwnb"); //这个是对称密钥,一会资源服务器那边也要指定为这个
- return converter;
- }
-
- @Bean
- public TokenStore tokenStore(JwtAccessTokenConverter converter){ //Token存储方式现在改为JWT存储
- return new JwtTokenStore(converter); //传入刚刚定义好的转换器
- }
- }
测试数据
- {
- "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2Nzg0NTU5NzUsInVzZXJfbmFtZSI6InRlc3QiLCJhdXRob3JpdGllcyI6WyJST0xFX1VTRVIiXSwianRpIjoiOWU1YWQ1YzQtMGMzYS00ZDk1LWJkMzAtYTRjNWIxYTJjYjQwIiwiY2xpZW50X2lkIjoid2ViIiwic2NvcGUiOlsiYm9vayIsInVzZXIiLCJib3Jyb3ciXX0.usX2dEmo33RIKFsavHYISxsZ90egECJxnmGrGBRz1ZM",
- "token_type": "bearer",
- "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJ0ZXN0Iiwic2NvcGUiOlsiYm9vayIsInVzZXIiLCJib3Jyb3ciXSwiYXRpIjoiOWU1YWQ1YzQtMGMzYS00ZDk1LWJkMzAtYTRjNWIxYTJjYjQwIiwiZXhwIjoxNjgxMDA0Nzc1LCJhdXRob3JpdGllcyI6WyJST0xFX1VTRVIiXSwianRpIjoiZDc5OGQxNWYtNmNlNi00ZmVmLTlhYmEtZTk0MWU4ODBhMWM4IiwiY2xpZW50X2lkIjoid2ViIn0.puqEiGA27R1DTQiRk7WQ6OIYhGJ0i87AkrRHK1G5dkA",
- "expires_in": 43199,
- "scope": "book user borrow",
- "jti": "9e5ad5c4-0c3a-4d95-bd30-a4c5b1a2cb40"
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。