SpringSecurity+Oauth2【授权码模式】+增强JWT实现单体应用资源访问控制

阅读本章节需要掌握springsecurity、oauth2协议、jwt


本次测试使用oauth2的授权码模式进行,和数据库交,互贴近实际生产。
  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. 创建配置文件 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 {

    /**
     * 认证服务器
     */
    @Configuration
    @EnableAuthorizationServer
    public class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {
        //注入自定义实现用户信息服务,网上大多是基于内存的操作,次实现表示从数据库中读取用户信息
        @Autowired
        private UserDetailsService userDetailsService;

        //数据源
        @Qualifier("dataSource")
        @Autowired
        private DataSource dataSource;

        //认证管理器authenticationManager 开启密码授权
        @Autowired
        private AuthenticationManager authenticationManager;

        //jwtToken增强,自定义实现token扩展
        @Autowired
        private TokenEnhancer jwtTokenEnhancer;

        //token存储,自定义实现保存到数据库中
        @Autowired
        private TokenStore tokenStore;

        //token转换器
        @Autowired
        private JwtAccessTokenConverter jwtAccessTokenConverter;

        //客户端信息,来源与DB
        @Bean
        public JdbcClientDetailsService clientDetailsService() {
            return new JdbcClientDetailsService(dataSource);
        }

        //自定义将自定授权保存数据库
        @Bean
        public ApprovalStore approvalStore() {
            return new JdbcApprovalStore(dataSource);
        }

        //将授权码保存数据库
        @Bean
        public AuthorizationCodeServices authorizationCodeServices() {
            return new JdbcAuthorizationCodeServices(dataSource);
        }

        //配置令牌端点(Token Endpoint)的安全约束.
        //授权服务安全配置,单体应用注意配置checkTokenAccess放行。
        @Override
        public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
            super.configure(security);
            //允许/oauth/token调用
            security.tokenKeyAccess("permitAll()")
                    //允许/oauth/check_token被调用
//                    .checkTokenAccess("permitAll()");
                    .checkTokenAccess("isAuthenticated()");
        }

         //配置客户端详情服务(ClientDetailsService)
         //客户端详情信息在这里进行初始化
         //通过数据库来存储调取详情信息
        //配置客户但详情从数据库读取,默认手动添加到oauth2客户端表中的数据
        @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());
        }

        /**
         *  配置授权(authorization)以及令牌(token)的访问端点和令牌服务(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())     //配置将授权码存放在oauth_code变中,默认存在内存中
                    .approvalStore(approvalStore())                             //配置审批存储oauth_approvals,存储用户审批过程,在一个月时间内不用再次审批
                    .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数组中
                enhancerChain.setTokenEnhancers(enhancers);
                //为什么不直接把jwtTokenEnhancer加在这个位置呢?
                endpoints.tokenEnhancer(enhancerChain)
                        .accessTokenConverter(jwtAccessTokenConverter);
            }
        }
    }
    /**
     * 资源服务器
     */
    @EnableResourceServer
    public class ResourcesServerConfig extends ResourceServerConfigurerAdapter {
        @Autowired
        private DefaultTokenServices tokenServices;
        @Override
        public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
            //资源id可再次手动设置任意字符串,如果不设置,则需要在数据oauth_client_details中的resource_ids填写固定值"oauth2-resource"
            resources.resourceId("res1");
            resources.tokenServices(tokenServices);
            super.configure(resources);
        }

        //配置需要拦截的资源,这里可扩展的比较多,自由发挥
        @Override
        public void configure(HttpSecurity http) throws Exception {
            http.antMatcher("/context")
                    .authorizeRequests()
                    .anyRequest()
                    .authenticated();
        }
    }
}

源码解读

资源服务器中配置的时候,需要注意有关资源id的配置:这里如果不配置,则在数据库中的oauth_client_details中的resource_ids填写固定值"oauth2-resource",如果配置,则需要和数据库中保持一致。

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());
        //非对称加密
        accessTokenConverter.setKeyPair(keyStoreKeyFactory.getKeyPair("zhan"));
//        accessTokenConverter.setVerifierKey(publicKey);
        //对称加密
//        accessTokenConverter.setSigningKey("123456");
        return accessTokenConverter;
    }
}

注意:这里需要强调一点的是必须向容器中注入DefaultTokenServices 的Bean,问什么呢,直接看源码就知道,这个类实现了认证的token和资源的token服务接口,在单体应用中它就用来生成和解析token

image.png

  1. 编写自定义token增强器
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 增强器        Jwt token 扩展
 *
 * @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();
        // 与登录时候放进去的UserDetail实现类一直查看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", "陕西省西安市");
//        //设置附加信息
//        ((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
//开启方法级别支持spel表达式的角色权限校验注解,粒度更细,更好控制
@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);
    }

    /**
     * 需要配置这个支持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();
    }

    /**
     * 配置认证信息
     * @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());
    }
}

其中比较重要的几个类:OAuth2AuthenticationManager认证管理,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);
    }

认证流程


授权流程


image.png

授权决策【这就是传说中的投票器机制】

AccessDecisionManager的投票机制
|
AffirmativeBased一票通过
UnanimousBased一票反对
ConsensusBased少数服从多数
AccessDecisionVoter访问决策投票器
RoleVoter角色投票
AuthenticatedVoter认证投票
有兴趣可以去看看源码,非常有意思!

附上本次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 登出


// 获取授权码
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的一个方法,他只告诉了Spring我只配置了一个我这个Adapter能处理哪个的url,它与authorizeRequests()没有任何关系。

http.authorizeRequests().antMatchers("/").hasRole("");
然后使用authorizeRequests().antMatchers()是告诉你在antMatchers()中指定的一个或多个路径,比如执行permitAll()或hasRole()。他们在第一个http.antMatcher()匹配时就会生效。

========================================================================================================

资源服务 (包含公钥)
认证服务  (包含私钥)
私钥用于springsecurity生成JWT令牌,公钥放于资源服务。用于访问资源

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是一个java提供得证书管理工具
    --alias:    密钥别名
    --keyalg:   使用得hash算法
    --keypass:  密钥访问得密码
    --keystore: 密钥库文件名   zhan.keystore保存了生成得证书
    --storepass:密钥库得访问密码

1、生成密钥证书  【RSA算法每个证书都包含公钥和私钥,私钥生成得令牌公钥可以去校验】

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报文

<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报文

<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.

有些系统可能默认允许记住或批准审批决策。检查

这样的逻辑,并相应地在授权请求上设置approved标志。
------------------------
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.

将身份验证请求放置到模型中,以便将其存储在会话中

申请批准或拒绝使用。这样我们可以确保auth请求来自会话,

因此,传递给approveOrDeny的任何身份验证请求参数都将被忽略并从会话中检索。

--------------------------------
[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]

微服务一般授权和资源服务器分开,这时候我们的思路是,在网关处同意拦截请求,验证token,符合直接将token发送给各个微服务,由各个问服务自己解析token

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,884评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,755评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,369评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,799评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,910评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,096评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,159评论 3 411
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,917评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,360评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,673评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,814评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,509评论 4 334
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,156评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,882评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,123评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,641评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,728评论 2 351