閱讀本章節(jié)需要掌握springsecurity废赞、oauth2協(xié)議徽龟、jwt
本次測試使用oauth2的授權(quán)碼模式進(jìn)行,和數(shù)據(jù)庫交唉地,互貼近實(shí)際生產(chǎn)据悔。
- 新建spring工程。添加依賴
<?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>spring-boot-oauth-jwt-server</groupId>
<artifactId>spring-boot-oauth-jwt-server</artifactId>
<version>1.0-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.3.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security.oauth</groupId>
<artifactId>spring-security-oauth2</artifactId>
<version>2.3.4.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-jwt</artifactId>
<version>1.0.9.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.7.0</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.3.2</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.8</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<!--此處可以防止把秘鑰放入編譯-->
<!--<resources>-->
<!--<resource>-->
<!--<directory>src/main/resources</directory>-->
<!--<filtering>true</filtering>-->
<!--<excludes>-->
<!--<exclude>*.jks</exclude>-->
<!--</excludes>-->
<!--</resource>-->
<!--</resources>-->
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<mainClass>com.buxiaoxia.Application</mainClass>
<addResources>true</addResources>
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- 編譯版本; -->
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
- 創(chuàng)建配置文件 Oauth2Config.java
package com.funtl.oauth2.server.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.core.userdetails.UserDetailsService;
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.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
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.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.approval.ApprovalStore;
import org.springframework.security.oauth2.provider.approval.JdbcApprovalStore;
import org.springframework.security.oauth2.provider.client.JdbcClientDetailsService;
import org.springframework.security.oauth2.provider.code.AuthorizationCodeServices;
import org.springframework.security.oauth2.provider.code.JdbcAuthorizationCodeServices;
import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
import org.springframework.security.oauth2.provider.token.TokenEnhancer;
import org.springframework.security.oauth2.provider.token.TokenEnhancerChain;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import javax.sql.DataSource;
import java.util.ArrayList;
import java.util.List;
@Configuration
public class Oauth2Config {
/**
* 認(rèn)證服務(wù)器
*/
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {
//注入自定義實(shí)現(xiàn)用戶信息服務(wù)耘沼,網(wǎng)上大多是基于內(nèi)存的操作极颓,次實(shí)現(xiàn)表示從數(shù)據(jù)庫中讀取用戶信息
@Autowired
private UserDetailsService userDetailsService;
//數(shù)據(jù)源
@Qualifier("dataSource")
@Autowired
private DataSource dataSource;
//認(rèn)證管理器authenticationManager 開啟密碼授權(quán)
@Autowired
private AuthenticationManager authenticationManager;
//jwtToken增強(qiáng),自定義實(shí)現(xiàn)token擴(kuò)展
@Autowired
private TokenEnhancer jwtTokenEnhancer;
//token存儲(chǔ)群嗤,自定義實(shí)現(xiàn)保存到數(shù)據(jù)庫中
@Autowired
private TokenStore tokenStore;
//token轉(zhuǎn)換器
@Autowired
private JwtAccessTokenConverter jwtAccessTokenConverter;
//客戶端信息菠隆,來源與DB
@Bean
public JdbcClientDetailsService clientDetailsService() {
return new JdbcClientDetailsService(dataSource);
}
//自定義將自定授權(quán)保存數(shù)據(jù)庫
@Bean
public ApprovalStore approvalStore() {
return new JdbcApprovalStore(dataSource);
}
//將授權(quán)碼保存數(shù)據(jù)庫
@Bean
public AuthorizationCodeServices authorizationCodeServices() {
return new JdbcAuthorizationCodeServices(dataSource);
}
//配置令牌端點(diǎn)(Token Endpoint)的安全約束.
//授權(quán)服務(wù)安全配置,單體應(yīng)用注意配置checkTokenAccess放行狂秘。
@Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
super.configure(security);
//允許/oauth/token調(diào)用
security.tokenKeyAccess("permitAll()")
//允許/oauth/check_token被調(diào)用
// .checkTokenAccess("permitAll()");
.checkTokenAccess("isAuthenticated()");
}
//配置客戶端詳情服務(wù)(ClientDetailsService)
//客戶端詳情信息在這里進(jìn)行初始化
//通過數(shù)據(jù)庫來存儲(chǔ)調(diào)取詳情信息
//配置客戶但詳情從數(shù)據(jù)庫讀取骇径,默認(rèn)手動(dòng)添加到oauth2客戶端表中的數(shù)據(jù)
@Bean
public ClientDetailsService jdbcClientDetailes() {
return new JdbcClientDetailsService(dataSource);
}
//客戶但詳情配置,基于JDBC
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
// clients.inMemory()
// .withClient("client")
// .secret(passwordEncoder.encode("secret"))
// .authorizedGrantTypes("authorization_code")
// .scopes("app")
// .redirectUris("https://www.baidu.com");
clients.withClientDetails(jdbcClientDetailes());
}
/**
* 配置授權(quán)(authorization)以及令牌(token)的訪問端點(diǎn)和令牌服務(wù)(token services)
*
* @param endpoints
* @throws Exception
*/
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
// endpoints.allowedTokenEndpointRequestMethods(HttpMethod.GET)
// .authorizationCodeServices(authorizationCodeServices);
endpoints.tokenStore(tokenStore)
.authorizationCodeServices(authorizationCodeServices()) //配置將授權(quán)碼存放在oauth_code變中者春,默認(rèn)存在內(nèi)存中
.approvalStore(approvalStore()) //配置審批存儲(chǔ)oauth_approvals既峡,存儲(chǔ)用戶審批過程,在一個(gè)月時(shí)間內(nèi)不用再次審批
.authenticationManager(authenticationManager)
.userDetailsService(userDetailsService)
.reuseRefreshTokens(true); //支持刷新令牌
if (jwtAccessTokenConverter != null && jwtTokenEnhancer != null) {
TokenEnhancerChain enhancerChain = new TokenEnhancerChain();
List<TokenEnhancer> enhancers = new ArrayList<>();
enhancers.add(jwtAccessTokenConverter);
enhancers.add(jwtTokenEnhancer);
//將自定義Enhancer加入EnhancerChain的delegates數(shù)組中
enhancerChain.setTokenEnhancers(enhancers);
//為什么不直接把jwtTokenEnhancer加在這個(gè)位置呢碧查?
endpoints.tokenEnhancer(enhancerChain)
.accessTokenConverter(jwtAccessTokenConverter);
}
}
}
/**
* 資源服務(wù)器
*/
@EnableResourceServer
public class ResourcesServerConfig extends ResourceServerConfigurerAdapter {
@Autowired
private DefaultTokenServices tokenServices;
@Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
//資源id可再次手動(dòng)設(shè)置任意字符串,如果不設(shè)置校仑,則需要在數(shù)據(jù)oauth_client_details中的resource_ids填寫固定值"oauth2-resource"
resources.resourceId("res1");
resources.tokenServices(tokenServices);
super.configure(resources);
}
//配置需要攔截的資源忠售,這里可擴(kuò)展的比較多,自由發(fā)揮
@Override
public void configure(HttpSecurity http) throws Exception {
http.antMatcher("/context")
.authorizeRequests()
.anyRequest()
.authenticated();
}
}
}
源碼解讀
資源服務(wù)器中配置的時(shí)候迄沫,需要注意有關(guān)資源id的配置:這里如果不配置稻扬,則在數(shù)據(jù)庫中的oauth_client_details中的resource_ids填寫固定值"oauth2-resource",如果配置羊瘩,則需要和數(shù)據(jù)庫中保持一致泰佳。
- 配置jwtTokenConfig
package com.funtl.oauth2.server.config;
import com.funtl.oauth2.jwt.MyJwtTokenEnhancer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.ClassPathResource;
import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
import org.springframework.security.oauth2.provider.token.TokenEnhancer;
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;
import org.springframework.security.oauth2.provider.token.store.KeyStoreKeyFactory;
/**
* @author zhan
* @since 2019-12-13 15:28
*/
@Configuration
public class JwtTokenConfig {
private static final String publicKey = "-----BEGIN PUBLIC KEY-----MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAgN0Ka7Xv+2xgoUtuHtqBnKljMyBe5YZ/Zo7Jo1H9P0AwVDzPbmrBfq2Y2oqdFlcAUBs0UwKJ0FuqP6IgoRqCTBb5NmQo9nhgC0FGLF26wiLID1P0+lXoX02mhj6yqAGZDo3tMgk0xJ9pRybnqQOWJzAkISfI71by/IpOm5BZzzTNGH7sW8yxdw8K8+tFquKLMbKQcAAUa9/9l5VvIyvUci63Xt5URCWb6IDtwCNhu+cCs3ZBX6hcrdQW0VP46nG14+6fm50FpVEnQAXowfagP/ipdJcA/54sJeJ/m2vHQEbS4lKHhDUrfgIbJBaUmtk5ZkufVRkMSryjuIO1IasLbwIDAQAB-----END PUBLIC KEY-----";
@Bean
// @ConditionalOnBean(JwtTokenEnhancer.class)
public TokenEnhancer jwtTokenEnhancer() {
return new MyJwtTokenEnhancer();
}
@Bean
public TokenStore jwtTokenStore() {
return new JwtTokenStore(jwtAccessTokenConverter());
}
@Bean
@Primary
public DefaultTokenServices tokenServices() {
DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
defaultTokenServices.setTokenStore(jwtTokenStore());
return defaultTokenServices;
}
/**
* token生成處理:指定簽名
*/
@Bean
public JwtAccessTokenConverter jwtAccessTokenConverter() {
JwtAccessTokenConverter accessTokenConverter = new JwtAccessTokenConverter();
KeyStoreKeyFactory keyStoreKeyFactory = new KeyStoreKeyFactory(new ClassPathResource("zhan.keystore"), "123456".toCharArray());
//非對(duì)稱加密
accessTokenConverter.setKeyPair(keyStoreKeyFactory.getKeyPair("zhan"));
// accessTokenConverter.setVerifierKey(publicKey);
//對(duì)稱加密
// accessTokenConverter.setSigningKey("123456");
return accessTokenConverter;
}
}
注意:這里需要強(qiáng)調(diào)一點(diǎn)的是必須向容器中注入DefaultTokenServices 的Bean,問什么呢,直接看源碼就知道尘吗,這個(gè)類實(shí)現(xiàn)了認(rèn)證的token和資源的token服務(wù)接口逝她,在單體應(yīng)用中它就用來生成和解析token
- 編寫自定義token增強(qiáng)器
package com.funtl.oauth2.jwt;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.token.TokenEnhancer;
import java.util.HashMap;
import java.util.Map;
/**
*
* token 增強(qiáng)器 Jwt token 擴(kuò)展
*
* @author zhan
* @since 2019-12-13 14:57
*/
public class MyJwtTokenEnhancer implements TokenEnhancer {
@Override
public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
String userName = authentication.getUserAuthentication().getName();
// 與登錄時(shí)候放進(jìn)去的UserDetail實(shí)現(xiàn)類一直查看link{SecurityConfiguration}
User user = (User) authentication.getUserAuthentication().getPrincipal();
/** 自定義一些token屬性 ***/
final Map<String, Object> additionalInformation = new HashMap<>();
additionalInformation.put("userName", userName);
additionalInformation.put("address", "陜西省西安市");
((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(additionalInformation);
// OAuth2AccessToken enhancedToken = super.enhance(accessToken, authentication);
return accessToken;
// Map<String, Object> info = new HashMap<>(2);
// info.put("username", "瑩瑩");
// info.put("age", 26);
// info.put("address", "陜西省西安市");
// //設(shè)置附加信息
// ((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(info);
// System.out.println(accessToken.getAdditionalInformation());
// return accessToken;
}
}
- 配置security的自定義配置
package com.funtl.oauth2.server.config;
import com.funtl.oauth2.server.config.service.UserDetailsServiceImpl;
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.method.configuration.EnableGlobalMethodSecurity;
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.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
/**
* @author zhan
* @since 2019-05-30 17:22
*/
@Configuration
@EnableWebSecurity
//開啟方法級(jí)別支持spel表達(dá)式的角色權(quán)限校驗(yàn)注解,粒度更細(xì)睬捶,更好控制
@EnableGlobalMethodSecurity(prePostEnabled = true, jsr250Enabled = true, securedEnabled = true)
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
super.configure(http);
}
@Override
public void configure(WebSecurity web) throws Exception {
super.configure(web);
}
/**
* 需要配置這個(gè)支持password模式
* support password grant type
* @return
* @throws Exception
*/
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Override
@Bean
public UserDetailsService userDetailsService(){
return new UserDetailsServiceImpl();
}
@Bean
public BCryptPasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
/**
* 配置認(rèn)證信息
* @param auth
* @throws Exception
*/
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// auth
// .inMemoryAuthentication()
// .withUser("admin").password(passwordEncoder().encode("123456")).roles("ADMIN")
// .and()
// .withUser("user").password(passwordEncoder().encode("123456")).roles("USER");
auth.userDetailsService(userDetailsService());
}
}
其中比較重要的幾個(gè)類:OAuth2AuthenticationManager認(rèn)證管理黔宛,OAuth2AuthenticationProcessingFilter 核心過濾器
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException,
ServletException {
final boolean debug = logger.isDebugEnabled();
final HttpServletRequest request = (HttpServletRequest) req;
final HttpServletResponse response = (HttpServletResponse) res;
try {
Authentication authentication = tokenExtractor.extract(request);
if (authentication == null) {
if (stateless && isAuthenticated()) {
if (debug) {
logger.debug("Clearing security context.");
}
SecurityContextHolder.clearContext();
}
if (debug) {
logger.debug("No token in request, will continue chain.");
}
}
else {
request.setAttribute(OAuth2AuthenticationDetails.ACCESS_TOKEN_VALUE, authentication.getPrincipal());
if (authentication instanceof AbstractAuthenticationToken) {
AbstractAuthenticationToken needsDetails = (AbstractAuthenticationToken) authentication;
needsDetails.setDetails(authenticationDetailsSource.buildDetails(request));
}
Authentication authResult = authenticationManager.authenticate(authentication);
if (debug) {
logger.debug("Authentication success: " + authResult);
}
eventPublisher.publishAuthenticationSuccess(authResult);
SecurityContextHolder.getContext().setAuthentication(authResult);
}
}
catch (OAuth2Exception failed) {
SecurityContextHolder.clearContext();
if (debug) {
logger.debug("Authentication request failed: " + failed);
}
eventPublisher.publishAuthenticationFailure(new BadCredentialsException(failed.getMessage(), failed),
new PreAuthenticatedAuthenticationToken("access-token", "N/A"));
authenticationEntryPoint.commence(request, response,
new InsufficientAuthenticationException(failed.getMessage(), failed));
return;
}
chain.doFilter(request, response);
}
認(rèn)證流程
授權(quán)流程
授權(quán)決策【這就是傳說中的投票器機(jī)制】
AccessDecisionManager的投票機(jī)制
|
AffirmativeBased一票通過
UnanimousBased一票反對(duì)
ConsensusBased少數(shù)服從多數(shù)
AccessDecisionVoter訪問決策投票器
RoleVoter角色投票
AuthenticatedVoter認(rèn)證投票
有興趣可以去看看源碼,非常有意思擒贸!
附上本次testing筆記
https://graph.qq.com/oauth2.0/show?which=Login&display=pc&response_type=code&client_id=101218304&redirect_uri=http://passport.itheima.com/connect/qq&state=b78bbdf538b7369ce3cf5169d506faab&scope=
http://localhost:8080/logout sprign security 登出
// 獲取授權(quán)碼
http://localhost:8080/oauth/authorize?response_type=code&client_id=test&redirect_uri=https://www.baidu.com&scope=all&state=hello
http://localhost:8081/oauth/authorize?client_id=client&response_type=code
http://localhost:13000/oauth/authorize?client_id=client&response_type=code
http://localhost:8080/oauth/check_token?token=
// 獲取token
http://localhost:8080/oauth/token?grant_type=authorization_code&code=XozVUL&client_id=test&redirect_uri=https://www.baidu.com/&scpoe=all
\A\$2a?\$\d\d\$[./0-9A-Za-z]{53} OAuth2.0 密碼正則
http.antMatcher("/").authorizeRequests();
大體意思就是antMatcher()``是HttpSecurity的一個(gè)方法臀晃,他只告訴了Spring我只配置了一個(gè)我這個(gè)Adapter能處理哪個(gè)的url觉渴,它與authorizeRequests()沒有任何關(guān)系。
http.authorizeRequests().antMatchers("/").hasRole("");
然后使用authorizeRequests().antMatchers()是告訴你在antMatchers()中指定的一個(gè)或多個(gè)路徑,比如執(zhí)行permitAll()或hasRole()徽惋。他們?cè)诘谝粋€(gè)http.antMatcher()匹配時(shí)就會(huì)生效案淋。
========================================================================================================
資源服務(wù) (包含公鑰)
認(rèn)證服務(wù) (包含私鑰)
私鑰用于springsecurity生成JWT令牌,公鑰放于資源服務(wù)险绘。用于訪問資源
keytool ‐list ‐rfc ‐‐keystore xc.keystore | openssl x509 ‐inform pem ‐pubkey
keytool -list -v -keystore kevin_key.jks -storepass 123456
keytool ‐list ‐rfc ‐‐keystore kevin_key.jks | openssl x509 ‐inform pem ‐pubkey
Keytool是一個(gè)java提供得證書管理工具
--alias: 密鑰別名
--keyalg: 使用得hash算法
--keypass: 密鑰訪問得密碼
--keystore: 密鑰庫文件名 zhan.keystore保存了生成得證書
--storepass:密鑰庫得訪問密碼
1踢京、生成密鑰證書 【RSA算法每個(gè)證書都包含公鑰和私鑰,私鑰生成得令牌公鑰可以去校驗(yàn)】
keytool -genkeypair -alias kevin_key -keyalg RSA -keypass 123456 -keystore kevin_key.jks -storepass 123456
keytool -genkeypair -alias zhan -keyalg RSA -keypass 123456 -keystore zhan.keystore -storepass 123456
2.查看證書信息:
keytool -list -v -keystore zhan.keystore -storepass 123456
keytool -list -keystore zhan.keystore
3.查看公鑰信息
keytool -list -rfc --keystore zhan.keystore | openssl x509 -inform pem -pubkey
-----BEGIN PUBLIC KEY-----MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAgN0Ka7Xv+2xgoUtuHtqBnKljMyBe5YZ/Zo7Jo1H9P0AwVDzPbmrBfq2Y2oqdFlcAUBs0UwKJ0FuqP6IgoRqCTBb5NmQo9nhgC0FGLF26wiLID1P0+lXoX02mhj6yqAGZDo3tMgk0xJ9pRybnqQOWJzAkISfI71by/IpOm5BZzzTNGH7sW8yxdw8K8+tFquKLMbKQcAAUa9/9l5VvIyvUci63Xt5URCWb6IDtwCNhu+cCs3ZBX6hcrdQW0VP46nG14+6fm50FpVEnQAXowfagP/ipdJcA/54sJeJ/m2vHQEbS4lKHhDUrfgIbJBaUmtk5ZkufVRkMSryjuIO1IasLbwIDAQAB-----END PUBLIC KEY-----
-------------------------------------------------------------------------------------------------
-------------------------------request header--------------------------------------------------------------------------------------------------------------
request報(bào)文
<method> <request-URL> <version>
<HEADERS>
<entity-body>
----------------------------------------
GET /login/code/image HTTP/1.1
Host: 133.64.135.164:8000
Connection: keep-alive
Authorization: Basic dGVzdDp0ZXN0
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.70 Safari/537.36
Accept: */*
Referer: http://133.64.135.164:8000/user/login
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7
-------------------------------response header------------------------------------------------------------------------------------------------------------
response報(bào)文
<version> <status> <reason-phrase>
<HEADERS>
<entity-body>
-----------------------------------------
HTTP/1.1 200 OK
X-Powered-By: Express
imagecodesession: 99a126fb-e962-441f-a88e-c69913375278
x-content-type-options: nosniff
x-xss-protection: 1; mode=block
cache-control: no-cache, no-store, max-age=0, must-revalidate
pragma: no-cache
expires: 0
x-frame-options: DENY
transfer-encoding: chunked
date: Mon, 30 Dec 2019 07:27:37 GMT
connection: close
{
"singleServerConfig":{
"address": "redis://127.0.0.1:6379",
"password": null,
"database": 1
},
"codec":{
"class":"org.redisson.codec.FstCodec"
},
"transportMode":"NIO"
}
Some systems may allow for approval decisions to be remembered or approved by default. Check for
such logic here, and set the approved flag on the authorization request accordingly.
有些系統(tǒng)可能默認(rèn)允許記住或批準(zhǔn)審批決策隆圆。檢查
這樣的邏輯漱挚,并相應(yīng)地在授權(quán)請(qǐng)求上設(shè)置approved標(biāo)志。
------------------------
Place auth request into the model so that it is stored in the session
for approveOrDeny to use. That way we make sure that auth request comes from the session,
so any auth request parameters passed to approveOrDeny will be ignored and retrieved from the session.
將身份驗(yàn)證請(qǐng)求放置到模型中渺氧,以便將其存儲(chǔ)在會(huì)話中
申請(qǐng)批準(zhǔn)或拒絕使用旨涝。這樣我們可以確保auth請(qǐng)求來自會(huì)話,
因此侣背,傳遞給approveOrDeny的任何身份驗(yàn)證請(qǐng)求參數(shù)都將被忽略并從會(huì)話中檢索白华。
--------------------------------
[org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@7945b206, org.springframework.security.web.context.SecurityContextPersistenceFilter@180b3819, org.springframework.security.web.header.HeaderWriterFilter@6f8e9d06,
org.springframework.security.web.csrf.CsrfFilter@6397248c, org.springframework.security.web.authentication.logout.LogoutFilter@3becc950, org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter@83bb0f, org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter@39666e42, org.springframework.security.web.authentication.ui.DefaultLogoutPageGeneratingFilter@7d42542, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@47272cd3, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@5e26f1ed, org.springframework.security.web.authentication.AnonymousAuthenticationFilter@4d09cade, org.springframework.security.web.session.SessionManagementFilter@2272cbb0, org.springframework.security.web.access.ExceptionTranslationFilter@53f0d09c, org.springframework.security.web.access.intercept.FilterSecurityInterceptor@1da1380b]
微服務(wù)一般授權(quán)和資源服務(wù)器分開,這時(shí)候我們的思路是贩耐,在網(wǎng)關(guān)處同意攔截請(qǐng)求弧腥,驗(yàn)證token,符合直接將token發(fā)送給各個(gè)微服務(wù)潮太,由各個(gè)問服務(wù)自己解析token