SpringSecurity+Oauth2【授權(quán)碼模式】+增強(qiáng)JWT實(shí)現(xiàn)單體應(yīng)用資源訪問控制

閱讀本章節(jié)需要掌握springsecurity废赞、oauth2協(xié)議徽龟、jwt


本次測試使用oauth2的授權(quán)碼模式進(jìn)行,和數(shù)據(jù)庫交唉地,互貼近實(shí)際生產(chǎn)据悔。
  1. 新建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>
  1. 創(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ù)庫中保持一致泰佳。

image.png

image.png

image.png

image.png
  1. 配置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

image.png

  1. 編寫自定義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;
    }
}

  1. 配置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)流程


image.png

授權(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

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末管搪,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子铡买,更是在濱河造成了極大的恐慌更鲁,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,406評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件奇钞,死亡現(xiàn)場離奇詭異澡为,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)景埃,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,732評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門媒至,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人谷徙,你說我怎么就攤上這事拒啰。” “怎么了完慧?”我有些...
    開封第一講書人閱讀 163,711評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵图呢,是天一觀的道長。 經(jīng)常有香客問我,道長蛤织,這世上最難降的妖魔是什么赴叹? 我笑而不...
    開封第一講書人閱讀 58,380評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮指蚜,結(jié)果婚禮上乞巧,老公的妹妹穿的比我還像新娘。我一直安慰自己摊鸡,他們只是感情好绽媒,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,432評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著免猾,像睡著了一般是辕。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上猎提,一...
    開封第一講書人閱讀 51,301評(píng)論 1 301
  • 那天获三,我揣著相機(jī)與錄音,去河邊找鬼锨苏。 笑死疙教,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的伞租。 我是一名探鬼主播贞谓,決...
    沈念sama閱讀 40,145評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼葵诈!你這毒婦竟也來了裸弦?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,008評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤作喘,失蹤者是張志新(化名)和其女友劉穎理疙,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體徊都,經(jīng)...
    沈念sama閱讀 45,443評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,649評(píng)論 3 334
  • 正文 我和宋清朗相戀三年广辰,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了暇矫。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,795評(píng)論 1 347
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡择吊,死狀恐怖李根,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情几睛,我是刑警寧澤房轿,帶...
    沈念sama閱讀 35,501評(píng)論 5 345
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響囱持,放射性物質(zhì)發(fā)生泄漏夯接。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,119評(píng)論 3 328
  • 文/蒙蒙 一纷妆、第九天 我趴在偏房一處隱蔽的房頂上張望盔几。 院中可真熱鬧,春花似錦掩幢、人聲如沸逊拍。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,731評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽芯丧。三九已至,卻和暖如春世曾,著一層夾襖步出監(jiān)牢的瞬間缨恒,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,865評(píng)論 1 269
  • 我被黑心中介騙來泰國打工度硝, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留肿轨,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,899評(píng)論 2 370
  • 正文 我出身青樓蕊程,卻偏偏與公主長得像椒袍,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子藻茂,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,724評(píng)論 2 354