欢送微信搜寻公众号【java 版 web 我的项目】获取资源:java 学习视频 / 设计模式笔记 / 算法手册 /java 我的项目
一、SpringCloud Security 简介
Spring Cloud Security 提供了一组原语,用于构建平安的应用程序和服务,而且操作简便。能够在内部(或集中)进行大量配置的申明性模型有助于实现大型合作的近程组件零碎,通常具备地方身份治理服务。它也十分易于在 Cloud Foundry 等服务平台中应用。在 Spring Boot 和 Spring Security OAuth2 的根底上,能够疾速创立实现常见模式的零碎,如单点登录,令牌中继和令牌替换。
性能:
- 从 Zuul 代理中的前端到后端服务中继 SSO 令牌
- 资源服务器之间的中继令牌
- 使 Feign 客户端体现得像
OAuth2RestTemplate
(获取令牌等)的拦截器 - 在 Zuul 代理中配置上游身份验证
二、繁多登录实现
1、在 SpringCloud——服务的注册与发现 Eureka 的根底上做批改
增加 spring-security 反对:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
增加配置:
server:
port: 8082
spring:
application:
name: eureka-client
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8081/eureka/
# fetch-registry: false
# register-with-eureka: false
# 平安认证的配置
security:
basic:
enabled: true
2、启动工程,浏览器拜访:http://localhost:8082/test
输出用户名和明码认证,用户名为 user,明码在程序启动时会输入到管制台上,如图:
登录胜利后浏览器显示:
test=============8082
三、配置 MySQL 数据库实现认证
1、增加相干依赖:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example.demo.security</groupId>
<artifactId>security-oauth2</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>security-oauth2</name>
<parent>
<groupId>com.example.demo</groupId>
<artifactId>springcloud-security</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-oauth2</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-velocity</artifactId>
<version>1.1.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
2、增加配置文件:
server:
port: 8081
spring:
application:
name: security-oauth2
datasource:
url: jdbc:mysql://127.0.0.1:3306/alan_oauth?allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8&useSSL=true&autoReconnect=true
username: root
password: admin
driver-class-name: com.mysql.jdbc.Driver
security:
basic:
enabled: false
3、相干 config 配置文件
创立受权配置信息类 OAuthSecurityConfig.java,申明 TokenStore 实现和 ClientDetails 的实现。
package com.example.demo.security.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
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.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.ClientDetailsService;
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.JdbcTokenStore;
import javax.sql.DataSource;
import java.util.concurrent.TimeUnit;
/**
* 门路:com.example.demo.security.config
* 类名:* 性能:《用一句形容一下》* 备注:* 创建人:typ
* 创立工夫:2018/9/26 14:25
* 批改人:* 批改备注:* 批改工夫:*/
@Configuration
public class OAuthSecurityConfig extends AuthorizationServerConfigurerAdapter{
@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private DataSource dataSource;
@Bean
public TokenStore tokenStore(){return new JdbcTokenStore(dataSource);
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {endpoints.authenticationManager(authenticationManager);
endpoints.tokenStore(tokenStore());
// 配置 TokenServices 参数
DefaultTokenServices tokenServices = new DefaultTokenServices();
tokenServices.setTokenStore(endpoints.getTokenStore());
tokenServices.setSupportRefreshToken(false);
tokenServices.setClientDetailsService(endpoints.getClientDetailsService());
tokenServices.setTokenEnhancer(endpoints.getTokenEnhancer());
tokenServices.setAccessTokenValiditySeconds((int) TimeUnit.DAYS.toSeconds(30)); // 30 天
endpoints.tokenServices(tokenServices);
}
@Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {//oauthServer.checkTokenAccess("isAuthenticated()");
oauthServer.checkTokenAccess("permitAll()");
oauthServer.allowFormAuthenticationForClients();}
@Bean
public ClientDetailsService clientDetails() {return new JdbcClientDetailsService(dataSource);
}
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {clients.withClientDetails(clientDetails());
clients.inMemory()
.withClient("client")
.secret("secret")
.authorizedGrantTypes("authorization_code")
.scopes("app");
}
}
平安服务配置类 OAuthWebConfig.java
package com.example.demo.security.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
/**
* 门路:com.example.demo.security.config
* 类名:* 性能:《用一句形容一下》* 备注:* 创建人:typ
* 创立工夫:2018/9/26 14:22
* 批改人:* 批改备注:* 批改工夫:*/
@Configuration
public class OAuthWebConfig extends WebSecurityConfigurerAdapter{
@Override
public void configure(WebSecurity web) throws Exception {web.ignoring()
.antMatchers("/favor.ico");
}
@Override
protected void configure(HttpSecurity http) throws Exception {super.configure(http);
}
}
自定义 provider 调用类 SsoAuthProvider.java
package com.example.demo.security.config;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.stereotype.Component;
import java.util.Collections;
/**
* 门路:com.example.demo.security.config
* 类名:* 性能:《用一句形容一下》* 备注:* 创建人:typ
* 创立工夫:2018/9/26 14:33
* 批改人:* 批改备注:* 批改工夫:*/
@Component
public class SsoAuthProvider implements AuthenticationProvider{private static final Logger log = LoggerFactory.getLogger(SsoAuthProvider.class);
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {log.info("自定义 provider 调用");
//// 返回一个 Token 对象示意登陆胜利
return new UsernamePasswordAuthenticationToken(authentication.getPrincipal(), authentication.getCredentials(), Collections.<GrantedAuthority>emptyList());
}
@Override
public boolean supports(Class<?> aClass) {return true;}
}
4、须要一个重定向的 controller 类
package com.example.demo.security.controller;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.SessionAttributes;
import java.util.Map;
/**
* 门路:com.example.demo.security.controller
* 类名:* 性能:《用一句形容一下》* 备注:* 创建人:typ
* 创立工夫:2018/9/26 14:30
* 批改人:* 批改备注:* 批改工夫:*/
@RestController
@SessionAttributes("authorizationRequest")
public class ErrorController {private static final Logger log = LoggerFactory.getLogger(ErrorController.class);
@RequestMapping("/oauth/error")
public String error(@RequestParam Map<String, String> parameters){String url = parameters.get("redirect_uri");
log.info("重定向: {}", url);
return "redirect:" + url + "?error=1";
}
}
5、启动类增加注解 @EnableAuthorizationServer
package com.example.demo.security;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.ProviderManager;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import java.util.Arrays;
@SpringBootApplication
@EnableAuthorizationServer
public class SecurityOauth2Application {public static void main(String[] args) {SpringApplication.run(SecurityOauth2Application.class, args);
}
@Autowired
private AuthenticationProvider authenticationProvider;
@Bean
public AuthenticationManager authenticationManager(){return new ProviderManager(Arrays.asList(authenticationProvider));
}
}
6、创立数据库及相干表
# Host: 127.0.0.1 (Version 5.7.21)
# Date: 2018-09-26 15:17:51
# Generator: MySQL-Front 6.0 (Build 2.20)
#
# Structure for table "clientdetails"
#
DROP TABLE IF EXISTS `clientdetails`;
CREATE TABLE `clientdetails` (`appId` varchar(128) NOT NULL,
`resourceIds` varchar(256) DEFAULT NULL,
`appSecret` varchar(256) DEFAULT NULL,
`scope` varchar(256) DEFAULT NULL,
`grantTypes` varchar(256) DEFAULT NULL,
`redirectUrl` varchar(256) DEFAULT NULL,
`authorities` varchar(256) DEFAULT NULL,
`access_token_validity` int(11) DEFAULT NULL,
`refresh_token_validity` int(11) DEFAULT NULL,
`additionalInformation` varchar(4096) DEFAULT NULL,
`autoApproveScopes` varchar(256) DEFAULT NULL,
PRIMARY KEY (`appId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
#
# Data for table "clientdetails"
#
#
# Structure for table "oauth_access_token"
#
DROP TABLE IF EXISTS `oauth_access_token`;
CREATE TABLE `oauth_access_token` (`token_id` varchar(256) DEFAULT NULL,
`token` blob,
`authentication_id` varchar(128) NOT NULL,
`user_name` varchar(256) DEFAULT NULL,
`client_id` varchar(256) DEFAULT NULL,
`authentication` blob,
`refresh_token` varchar(256) DEFAULT NULL,
PRIMARY KEY (`authentication_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
#
# Data for table "oauth_access_token"
#
#
# Structure for table "oauth_approvals"
#
DROP TABLE IF EXISTS `oauth_approvals`;
CREATE TABLE `oauth_approvals` (`userId` varchar(256) DEFAULT NULL,
`clientId` varchar(256) DEFAULT NULL,
`scope` varchar(256) DEFAULT NULL,
`status` varchar(10) DEFAULT NULL,
`expiresAt` datetime DEFAULT NULL,
`lastModifiedAt` datetime DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
#
# Data for table "oauth_approvals"
#
#
# Structure for table "oauth_client_details"
#
DROP TABLE IF EXISTS `oauth_client_details`;
CREATE TABLE `oauth_client_details` (`client_id` varchar(128) NOT NULL,
`resource_ids` varchar(256) DEFAULT NULL,
`client_secret` varchar(256) DEFAULT NULL,
`scope` varchar(256) DEFAULT NULL,
`authorized_grant_types` varchar(256) DEFAULT NULL,
`web_server_redirect_uri` varchar(256) DEFAULT NULL,
`authorities` varchar(256) DEFAULT NULL,
`access_token_validity` int(11) DEFAULT NULL,
`refresh_token_validity` int(11) DEFAULT NULL,
`additional_information` varchar(4096) DEFAULT NULL,
`autoapprove` varchar(256) DEFAULT NULL,
PRIMARY KEY (`client_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
#
# Data for table "oauth_client_details"
#
INSERT INTO `oauth_client_details` VALUES ('client',NULL,'secret','app','authorization_code','http://www.baidu.com',NULL,NULL,NULL,NULL,NULL);
#
# Structure for table "oauth_client_token"
#
DROP TABLE IF EXISTS `oauth_client_token`;
CREATE TABLE `oauth_client_token` (`token_id` varchar(256) DEFAULT NULL,
`token` blob,
`authentication_id` varchar(128) NOT NULL,
`user_name` varchar(256) DEFAULT NULL,
`client_id` varchar(256) DEFAULT NULL,
PRIMARY KEY (`authentication_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
#
# Data for table "oauth_client_token"
#
#
# Structure for table "oauth_code"
#
DROP TABLE IF EXISTS `oauth_code`;
CREATE TABLE `oauth_code` (`code` varchar(256) DEFAULT NULL,
`authentication` blob
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
#
# Data for table "oauth_code"
#
#
# Structure for table "oauth_refresh_token"
#
DROP TABLE IF EXISTS `oauth_refresh_token`;
CREATE TABLE `oauth_refresh_token` (`token_id` varchar(256) DEFAULT NULL,
`token` blob,
`authentication` blob
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
#
# Data for table "oauth_refresh_token"
#
在 oauth_client_details 表中增加一条数据
INSERT INTO `oauth_client_details` VALUES ('client',NULL,'secret','app','authorization_code','http://www.baidu.com',NULL,NULL,NULL,NULL,NULL);
启动工程,浏览器拜访:
http://localhost:8081/oauth/authorize?client_id=client&response_type=code&redirect_uri=http://www.baidu.com
点击 Authorize 会跳转到百度页面,因为数据库中配置的是百度页面。
四、OAuth 的思路
OAuth 在 ” 客户端 ” 与 ” 服务提供商 ” 之间,设置了一个受权层(authorization layer)。” 客户端 ” 不能间接登录 ” 服务提供商 ”,只能登录受权层,以此将用户与客户端辨别开来。” 客户端 ” 登录受权层所用的令牌(token),与用户的明码不同。用户能够在登录的时候,指定受权层令牌的权限范畴和有效期。
“ 客户端 ” 登录受权层当前,” 服务提供商 ” 依据令牌的权限范畴和有效期,向 ” 客户端 ” 凋谢用户贮存的材料。
OAuth 2.0 的运行流程:
(A)用户关上客户端当前,客户端要求用户给予受权。
(B)用户批准给予客户端受权。
(C)客户端应用上一步取得的受权,向认证服务器申请令牌。
(D)认证服务器对客户端进行认证当前,确认无误,批准发放令牌。
(E)客户端应用令牌,向资源服务器申请获取资源。
(F)资源服务器确认令牌无误,批准向客户端凋谢资源。
在下面六个步骤之中,B 是要害,即用户怎样才能给于客户端受权。有了这个受权当前,客户端就能够获取令牌,进而凭令牌获取资源。
五、客户端的受权模式
客户端必须失去用户的受权(authorization grant),能力取得令牌(access token)。
OAuth 2.0 定义了四种受权形式:
- 受权码模式(authorization code)
- 简化模式(implicit)
- 明码模式(resource owner password credentials)
- 客户端模式(client credentials)
1、受权码模式
受权码模式(authorization code)是性能最残缺、流程最紧密的受权模式。它的特点就是通过客户端的后盾服务器,与 ” 服务提供商 ” 的认证服务器进行互动。
步骤如下:
(A)用户拜访客户端,后者将前者导向认证服务器。
(B)用户抉择是否给予客户端受权。
(C)假如用户给予受权,认证服务器将用户导向客户端当时指定的 ” 重定向 URI”(redirection URI),同时附上一个受权码。
(D)客户端收到受权码,附上新近的 ” 重定向 URI”,向认证服务器申请令牌。这一步是在客户端的后盾的服务器上实现的,对用户不可见。
(E)认证服务器核查了受权码和重定向 URI,确认无误后,向客户端发送拜访令牌(access token)和更新令牌(refresh token)。
2、简化模式
简化模式(implicit grant type)不通过第三方应用程序的服务器,间接在浏览器中向认证服务器申请令牌,跳过了 ” 受权码 ” 这个步骤,因而得名。所有步骤在浏览器中实现,令牌对访问者是可见的,且客户端不须要认证。
步骤如下:
(A)客户端将用户导向认证服务器。
(B)用户决定是否给于客户端受权。
(C)假如用户给予受权,认证服务器将用户导向客户端指定的 ” 重定向 URI”,并在 URI 的 Hash 局部蕴含了拜访令牌。
(D)浏览器向资源服务器发出请求,其中不包含上一步收到的 Hash 值。
(E)资源服务器返回一个网页,其中蕴含的代码能够获取 Hash 值中的令牌。
(F)浏览器执行上一步取得的脚本,提取出令牌。
(G)浏览器将令牌发给客户端。
3、明码模式
明码模式(Resource Owner Password Credentials Grant)中,用户向客户端提供本人的用户名和明码。客户端应用这些信息,向 ” 服务商提供商 ” 索要受权。
在这种模式中,用户必须把本人的明码给客户端,然而客户端不得贮存明码。这通常用在用户对客户端高度信赖的状况下,比方客户端是操作系统的一部分,或者由一个驰名公司出品。而认证服务器只有在其余受权模式无奈执行的状况下,能力思考应用这种模式。
步骤如下:
(A)用户向客户端提供用户名和明码。
(B)客户端将用户名和明码发给认证服务器,向后者申请令牌。
(C)认证服务器确认无误后,向客户端提供拜访令牌。
4、客户端模式
客户端模式(Client Credentials Grant)指客户端以本人的名义,而不是以用户的名义,向 ” 服务提供商 ” 进行认证。严格地说,客户端模式并不属于 OAuth 框架所要解决的问题。在这种模式中,用户间接向客户端注册,客户端以本人的名义要求 ” 服务提供商 ” 提供服务,其实不存在受权问题。
步骤如下:
(A)客户端向认证服务器进行身份认证,并要求一个拜访令牌。
(B)认证服务器确认无误后,向客户端提供拜访令牌。
六、更新令牌
如果用户拜访的时候,客户端的 ” 拜访令牌 ” 曾经过期,则须要应用 ” 更新令牌 ” 申请一个新的拜访令牌。
客户端收回更新令牌的 HTTP 申请,蕴含以下参数:
- granttype:示意应用的受权模式,此处的值固定为 ”refreshtoken”,必选项。
- refresh_token:示意早前收到的更新令牌,必选项。
- scope:示意申请的受权范畴,不能够超出上一次申请的范畴,如果省略该参数,则示意与上一次统一。
作者:程序员大本营
起源:https://www.pianshen.com/arti…
近期热文举荐:
SpringCloud 微服务电商我的项目教程