当前位置:   article > 正文

security-oauth2(自定义配置)

security-oauth2(自定义配置)

整体介绍

security-oauth2 提供了一套完善的token认证授权体系,同时也提供一些配置类,让我们继承,重写的手段,做自己想要的配置。token的存储方式有多种,本章内容只讲解JWT存储方式的配置

1. 利用java提供的keytool工具生成密钥 ( .jks 或者 .keystore 文件)

打开黑窗口,运行命令:keytool -genkeypair -alias 【别名】-keyalg 【加密算法】 -keypass 【私钥的密码】 -keystore 【密钥库的名称】.【密钥库的后缀】 -storepass 【密钥库口令】

完整案列:keytool -genkeypair -alias alias -keyalg RSA -keypass keypass -keystore test.keystore -storepass storepass

命令执行之后,会弹出如下窗口
在这里插入图片描述
最后输入y,敲回车结束窗口,随即会在黑窗口当前目录下产生一个名为"test.keystore"的文件,这个就是密钥,其中包含了私钥和公钥

继续执行命令(查看密钥):keytool -list -rfc --keystore test.keystore | openssl x509 -inform pem -pubkey
会看到如下内容:

-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAi4gx+aC53QDguQ0MWaBe
cRM62P8mEAQSQsp9wrn2Sfa+DQX3pUB2HxpnDYehSvkNCjn3cFrCIFf4r4szopAd
Ay6SNblETXD8td1nzNTRdC/uR4uzUo3JCvz1uYpu9hEfPmmvkC6YehnjIRP13HOh
WzdnW6qdGB15CDlvySjDxli1LX6xbKYXZ6NjC8J5Zb8xkjXOEiiOqpNwwtDlYL/R
1eSCvCJWiOQBGKl9/cjFW38B4us6l2m4L8dW6fzbFwC/lsAIFydvP0X/qdjN3htg
YivJP1MQVc9Nb8Q/Xs5drQcqZeZ5VLK7lzy8MkcjG2dA8XWswRmNIUxyAH7jSpzf
OQIDAQAB
-----END PUBLIC KEY-----
-----BEGIN CERTIFICATE-----
MIIDQzCCAiugAwIBAgIEcTS6tjANBgkqhkiG9w0BAQsFADBSMQswCQYDVQQGEwJj
bjELMAkGA1UECBMCc2gxCzAJBgNVBAcTAnNoMQ0wCwYDVQQKEwRoYW5kMQ0wCwYD
VQQLEwRoYW5kMQswCQYDVQQDEwJldjAeFw0xOTA1MzAwNzAzMTdaFw0xOTA4Mjgw
NzAzMTdaMFIxCzAJBgNVBAYTAmNuMQswCQYDVQQIEwJzaDELMAkGA1UEBxMCc2gx
DTALBgNVBAoTBGhhbmQxDTALBgNVBAsTBGhhbmQxCzAJBgNVBAMTAmV2MIIBIjAN
BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAi4gx+aC53QDguQ0MWaBecRM62P8m
EAQSQsp9wrn2Sfa+DQX3pUB2HxpnDYehSvkNCjn3cFrCIFf4r4szopAdAy6SNblE
TXD8td1nzNTRdC/uR4uzUo3JCvz1uYpu9hEfPmmvkC6YehnjIRP13HOhWzdnW6qd
GB15CDlvySjDxli1LX6xbKYXZ6NjC8J5Zb8xkjXOEiiOqpNwwtDlYL/R1eSCvCJW
iOQBGKl9/cjFW38B4us6l2m4L8dW6fzbFwC/lsAIFydvP0X/qdjN3htgYivJP1MQ
Vc9Nb8Q/Xs5drQcqZeZ5VLK7lzy8MkcjG2dA8XWswRmNIUxyAH7jSpzfOQIDAQAB
oyEwHzAdBgNVHQ4EFgQUarJgnmi/5Xk6lGlr0BXjZ1VPxpUwDQYJKoZIhvcNAQEL
BQADggEBABbn5ORbO+xAG1DNVOp8BKsdkoDkB9WdTRwtIvqkSWq55lF0Rhbs8NPM
A/CTUPIfHTEl8ACxTKBORLhtmY2O9wwxTX0iSVUgfPzBAoOldb9FfXhf6OJpgrbT
Qz8rNbXMgvdRppZ7RH6Uqmv74HBoueMKfAKOFqh3kVjnsumWZOvoFIJDcx9z9Uc8
hLoNUBTdvNL3RlpGJBc55vPHVs47RUqOX5iH33w+mnEM4Jg9bB3EGjCBi2yqeHog
y8JpqcJLrgtIugDH+pbDRd4RbYRzfEah0S7oHMTNbUmZBUK+c+reZgFCbHal+yup
gRannJ06ijk8Jcc2Xs20HFQ9FYuoclE=
-----END CERTIFICATE-----
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

上面内容中的 BEGIN PUBLIC KEY 至 END PUBLIC KEY的部分,就是密钥中的公钥 (公钥可以先粘贴复制出来,后需要用到)

将上一步骤中的"test.keystore"文件放在 maven的resources资源目录下;

token(令牌)存储方式有JWT存储,JDBC存储,内存存储,redis存储及其他存储方式

JWT( json web token)是一种用于双方之间传递安全信息的简洁的、URL安全的表述性声明规范,也是一种token。

JWT由三部分组成:
Header 头部:算法和存储类型信息
Payload 负载:身份信息或者自定义的信息
Signature 签名: RSA签名信息(前文中的密钥,也是通过RSA算法生成的)

使用JWT生成的token大致长这样:

eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJtc2ctMSI6Iumdk-S7lCIsIm1zZy0yIjoi6Z2T5aWzIiwidXNlcl9uYW1lIjoiZXYiLCJzY29wZSI6WyJyZWFkIl0sImV4cCI6MTU1OTM2NjA1OCwiYXV0aG9yaXRpZXMiOlsiUk9MRV9VU0VSIl0sImp0aSI6IjVhMDdjYmUyLTEzNDYtNDkwNi1hNDE3LWIxMGYyNWEzM2FjMSIsImNsaWVudF9pZCI6ImNsaWVudEVWIn0.g774D_ITXavxxHdeZ11X_RywCVAMTRrkMpEcCkMMZyk8BYrlHGmTb3ACIeAOWEIyNLXJe06c4vYZaEfrFobXwvFaaH8nZtOUyK_72HziVPfigstOI-ehFivUtL–BPvsERF39gH26yAY_tjWNFhqu8MYo2CvlZMEWGBTdnd5tK8hcq8_w85KjXoggVt-7KXYYnlLVeo-xJOvsEeNpaor0VzFIN61Dfbnj-nB0CaPxsxlT8WC_33AbXvtHnJVqPzQIA3lKRhRaGuRGExZx_BDhL531T2NMlP-NkzRxrausf5fSTegfa-bjrNZh9dg-Pxv3yzRyFIfDxkJ-BJMaQR7KQ

上面这个token,是一个json字符串通过RSA算加密得来的,而这个json字符串是可以通过 https://jwt.io 解析出来的在这里插入图片描述
解析后得到的json字符串大概长这样(下文会讲解这个json字符串是怎么来的):

{"msg-1":"靓仔","msg-2":"靓女","user_name":"ev","scope":["read"],"exp":1559377994,"authorities":["ROLE_USER"],"jti":"dccd734e-5c43-4018-bc62-addefb429c56","client_id":"clientEV"}
  • 1

上面这个token以“.”分割成三部分:分别对应JWT的三个结构:

Header :eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9 --> 解码 --> 得到算法和存储类型信息
Payload : eyJtc2ctMSI6Iumdk-S7lCIsIm1zZy0yIjoi6Z2T5aWzIiwidXNlcl9uYW1lIjoiZXYiLCJzY29wZSI6WyJyZWFkIl0sImV4cCI6MTU1OTM2NjA1OCwiYXV0aG9yaXRpZXMiOlsiUk9MRV9VU0VSIl0sImp0aSI6IjVhMDdjYmUyLTEzNDYtNDkwNi1hNDE3LWIxMGYyNWEzM2FjMSIsImNsaWVudF9pZCI6ImNsaWVudEVWIn0 --> 解码 -->  得到上面这样的json字符串
Signature :g774D_ITXavxxHdeZ11X_RywCVAMTRrkMpEcCkMMZyk8BYrlHGmTb3ACIeAOWEIyNLXJe06c4vYZaEfrFobXwvFaaH8nZtOUyK_72HziVPfigstOI-ehFivUtL--BPvsERF39gH26yAY_tjWNFhqu8MYo2CvlZMEWGBTdnd5tK8hcq8_w85KjXoggVt-7KXYYnlLVeo-xJOvsEeNpaor0VzFIN61Dfbnj-nB0CaPxsxlT8WC_33AbXvtHnJVqPzQIA3lKRhRaGuRGExZx_BDhL531T2NMlP-NkzRxrausf5fSTegfa-bjrNZh9dg-Pxv3yzRyFIfDxkJ-BJMaQR7KQ --> 解码 --> 签名算法
  • 1
  • 2
  • 3

2. 自定义配置

2.1 配置TokenStore

核心配置之一,代码块中有注释,这里只需要知道这里怎么配置的,配置起什么作用就行了,具体配置是何时被用到的,不是本章重点,会在本人博客的其它文章中详细说明

@Component
public class TokenStoreConfig {

    @Bean("keyProp")
    public KeyProperties keyProperties() {
        return new KeyProperties();
    }
    //前文中生成的 test.keystore 文件在resources资源文件夹下的路径
    private String location = "test.keystore";
    // 生成 test.keystore 文件时候所用的【密钥库口令】
    private String secret = "storepass";
     // 生成 test.keystore 文件时候所用的【别名】
    private String alias = "alias";
    // 生成 test.keystore 文件时候所用的【私钥的密码】
    private String password = "keypass";
    // 生成的秘钥中的 PUBLIC KEY 部分
    private String publicKey = "-----BEGIN PUBLIC KEY-----\n" +
            "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsn4FPljPEtJCDmXMEoEK\n" +
            "xLCMl5rmd8MUxFVBhwUZGSH71h1Zphaxm9EvSulJQm+FzcldJYTeIDcQYtEl1kbQ\n" +
            "4Fmq840Iy3JSLF1Z9WXpddIzB4PLkrJwFYAXZAR351jbYGqUbzWWjJEOGLP6Yvzb\n" +
            "BrN6DzEYamoSwGUl8R93h1oRUHR3tVqdbMcjmyllvY7N9Qgk9lAldm6CcgavMqbm\n" +
            "USp2X64CgAtdwDixWSO3eCucpXX6ocwaEnUB4XWTXl76OhilZ0WSXXHXOuDZGllj\n" +
            "7fhmL0Hyo4bfy3PuQ9BdCJqE54SIELGxrTvapgLqwWhngJlnHSAGqRMkNxCFmwCk\n" +
            "/wIDAQAB\n" +
            "-----END PUBLIC KEY-----";

    /**
     * TokenStore是一个接口,他有五个直接子类,分别是:
     * JwtTokenStore jwt方式存储
     * JdbcTokenStore 数据库方式存储
     * InMemoryTokenStore 内存方式存储
     * 这里指定了是以JWT方式存储
     */
    @Bean
    public TokenStore tokenStore(JwtAccessTokenConverter jwtAccessTokenConverter) {
        //JWT方式存储,需要JWT令牌转换器,下面jwtAccessTokenConverter()方法中自定义了一个JWT令牌转换器
        return new JwtTokenStore(jwtAccessTokenConverter);
    }

    /**
     * 自定义JWT令牌转换器,交给Spring
     * JWT令牌转换器需要密钥对
     * 密钥对需要密钥文件,即( .jks 或者 .keystore) 文件,该文件里保存了密钥信息,密钥包含了私钥和公钥
     *
     * @return
     */
    @Bean
    public JwtAccessTokenConverter jwtAccessTokenConverter() {

        JwtAccessTokenConverter jwtAccessTokenConverter = new MyJwtAccessTokenConverter();
        // ================= 加密相关配置 =====================
        ClassPathResource resource = new ClassPathResource(location);
        KeyStoreKeyFactory keyStoreFactory = new KeyStoreKeyFactory(resource, secret.toCharArray());
        KeyPair keyPair = keyStoreFactory.getKeyPair(alias, password.toCharArray());
        //为自定义的JWT令牌转换器设置密钥对(密钥对包含了公钥和私钥,公钥用于加密令牌,私钥用于解密令牌)
        jwtAccessTokenConverter.setKeyPair(keyPair);

        // ================= 解密相关配置 ======================
        DefaultAccessTokenConverter defaultAccessTokenConverter = new DefaultAccessTokenConverter();
        defaultAccessTokenConverter.setUserTokenConverter(new MyDefaultUserAuthenticationConverter());
        jwtAccessTokenConverter.setAccessTokenConverter(defaultAccessTokenConverter);
        jwtAccessTokenConverter.setVerifierKey(publicKey);

        return jwtAccessTokenConverter;
    }

    class MyDefaultUserAuthenticationConverter extends DefaultUserAuthenticationConverter {
    	//在token的解密过程中,可以在extractAuthentication()方法中处理从token中解析出来的用户信息
        @Override
        public Authentication extractAuthentication(Map<String, ?> map) {
            if (map.containsKey(USERNAME)) {
                List<GrantedAuthority> authorities = AuthorityUtils.commaSeparatedStringToAuthorityList(StringUtils
                        .collectionToCommaDelimitedString((Collection<?>) map.get(AccessTokenConverter.AUTHORITIES)));
                // CustomUserDetails 是自定义的实体类,继承了 User 类,实现自定义用户信息
                CustomUserDetails userDetails = new CustomUserDetails((String) map.get(USERNAME), "admin", authorities);
                userDetails.setOrganizationName("智商有限公司");
                UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(userDetails, "N/A", authorities);
                return usernamePasswordAuthenticationToken;
            }
            return null;
        }
    }

	
    class MyJwtAccessTokenConverter extends JwtAccessTokenConverter {
		//在token的加密过程中,可以在enhance()方法中处理即将加密到token中的用户信息
        @Override
        public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
            DefaultOAuth2AccessToken result = new DefaultOAuth2AccessToken(accessToken);
            Map<String, Object> info = new LinkedHashMap<String, Object>(accessToken.getAdditionalInformation());
            String tokenId = result.getValue();
            if (!info.containsKey(TOKEN_ID)) {
                info.put(TOKEN_ID, tokenId);
            }
            // ====================================
            info.put("age", "18");//添加年龄,18岁
            // ====================================
            result.setAdditionalInformation(info);
            //super.encode(result, authentication) 用于加密信息
            result.setValue(super.encode(result, authentication));
            result.setRefreshToken(accessToken.getRefreshToken());
            result.setExpiration(accessToken.getExpiration());
            return result;
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106

2.2 配置AuthorizationServerConfigurerAdapter

@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {

    @Autowired
    private ApplicationContext applicationContext;

	//上文中配置的 TokenStore
    @Autowired
    private TokenStore tokenStore;

    @Autowired
    private OAuth2ClientProperties oAuth2ClientProperties;

    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired(required = false)
    private JdbcClientDetailsService jdbcClientDetailsService;

    //令牌失效时间
    public int accessTokenValiditySeconds = 3600;

    //刷新令牌失效时间
    public int refreshTokenValiditySeconds;

    //是否可以重用刷新令牌
    public boolean isReuseRefreshToken;

    //是否支持刷新令牌
    public boolean isSupportRefreshToken;

    public AuthorizationServerConfig() {
        this((int) TimeUnit.DAYS.toSeconds(1), 0, false, false);
    }


    public AuthorizationServerConfig(int accessTokenValiditySeconds, int refreshTokenValiditySeconds, boolean isReuseRefreshToken, boolean isSupportRefreshToken) {
        this.accessTokenValiditySeconds = accessTokenValiditySeconds;
        this.refreshTokenValiditySeconds = refreshTokenValiditySeconds;
        this.isReuseRefreshToken = isReuseRefreshToken;
        this.isSupportRefreshToken = isSupportRefreshToken;
    }

    /**
     * 配置授权服务器端点,如令牌存储,令牌自定义,用户批准和授权类型,不包括端点安全配置
     */
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {

        DefaultTokenServices defaultTokenServices = new DefaultTokenServices();

        //设置token存储方式,在AuthJWTToken中定义了JwtTokenStore方式存储
        defaultTokenServices.setTokenStore(tokenStore);
        /**
         * 设置token"加强者",因为是jwt方式存储,所以需要一个jwt令牌转换器,JwtAccessTokenConverter继承了TokenEnhancer
         * 而TokenEnhancer中有enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication)方法,该方法给加强token
         * 下面这句代码,会找到TokenEnhancer接口的实现类(AuthJWTTokenStoreDecode.MyJwtAccessTokenConverter extends JwtAccessTokenConverter implements TokenEnhancer, AccessTokenConverter, InitializingBean)
         */
        Collection<TokenEnhancer> tokenEnhancers = applicationContext.getBeansOfType(TokenEnhancer.class).values();
        TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
        tokenEnhancerChain.setTokenEnhancers(new ArrayList<>(tokenEnhancers));
        defaultTokenServices.setTokenEnhancer(tokenEnhancerChain);

        /**
         * 设置默认值
         */
        defaultTokenServices.setReuseRefreshToken(isReuseRefreshToken);
        defaultTokenServices.setSupportRefreshToken(isSupportRefreshToken);
        defaultTokenServices.setAccessTokenValiditySeconds(accessTokenValiditySeconds);
        defaultTokenServices.setRefreshTokenValiditySeconds(refreshTokenValiditySeconds);

        /*//若通过 JDBC 存储令牌
        if (Objects.nonNull(jdbcClientDetailsService)){
            defaultTokenServices.setClientDetailsService(jdbcClientDetailsService);
        }*/

        /**
         * 如果用密码模式验证,则需要配置AuthenticationManager
         */
        endpoints
                .authenticationManager(authenticationManager) //todo : 不知道authenticationManager的实现类是哪一个
                .userDetailsService(new CustomUserDetailsServiceImpl())
                .tokenServices(defaultTokenServices);
    }

    /**
     * 配置客户端详情
     *
     * @param clients
     * @throws Exception
     */
    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {

        clients.inMemory()                          // 使用内存存储客户端信息
                .withClient(oAuth2ClientProperties.getClientId())       // client_id
                /*
                 * security5.0版本之后,如果DelegatingPasswordEncoder的默认密码加密是BCryptPasswordEncoder , 那么此处必须给secret加密,因为再源码中会校验它
                 * */
                .secret(new BCryptPasswordEncoder().encode(oAuth2ClientProperties.getClientSecret()))                  // client_secret
                .authorizedGrantTypes("authorization_code", "password")     // 该client允许的授权类型
                .accessTokenValiditySeconds(3600)               // Token 的有效期
                .scopes("read")                    // 允许的授权范围
                .autoApprove(true);                  //登录后绕过批准询问(/oauth/confirm_access)
    }


    /**
     * 配置授权服务器端点的安全
     *
     * @param oauthServer
     * @throws Exception
     */
    @Override
    public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
        /**
         * 默认访问安全规则是denyAll(),即默认情况下是关闭的,请求调不通
         * 在资源服务器中,可能会调用oauth/token_key 来请求获取公钥,如果这里调不通,资源服务就没办法获取公钥,就没办法对jwt令牌的签名算法进行解密
         */
        oauthServer
                .tokenKeyAccess("permitAll()")
                .checkTokenAccess("permitAll()");
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124

AuthorizationServerConfigurerAdapter 的实例是通过@Configuration注解的形式注入到spring中的,它主要有三个配置方法:

2.3 配置WebSecurityConfigurerAdapter

代码块中有注释进行具体解释,阅读注释即可

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {


    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }


    /**
     * 设置defaultPasswordEncoderForMatches为NoOpPasswordEncoder
     * https://blog.csdn.net/alinyua/article/details/80219500 security5.0版本之后有所改动,这个网址讲解的很到位
     *
     * @return
     */
    @Bean
    public PasswordEncoder passwordEncoder() {

        FastJsonHttpMessageConverter a;
        MappingJackson2HttpMessageConverter b;
        WebMvcConfigurer c;


        DelegatingPasswordEncoder delegatingPasswordEncoder = (DelegatingPasswordEncoder) PasswordEncoderFactories.createDelegatingPasswordEncoder();
        delegatingPasswordEncoder.setDefaultPasswordEncoderForMatches(new BCryptPasswordEncoder());
        /**
         * NoOpPasswordEncoder被认为是不安全的,因为源码里面,实际没有编码密码
         * delegatingPasswordEncoder.setDefaultPasswordEncoderForMatches(NoOpPasswordEncoder.getInstance());
         */
        return delegatingPasswordEncoder;
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
    	//如果一个站点欺骗用户提交请求到其他服务器的话,就会发生CSRF攻击。 
    // Spring Security3.2开启,默认会启用CSRF防护
        http.csrf().disable();
    }
 /**
     * 跨域请求
     * 出于安全考虑,浏览器会限制从脚本内发起的跨域HTTP请求。跨域资源共享机制允许 Web 应用服务器进行跨域访问控制,
     * 从而使跨域数据传输得以安全进行。浏览器支持在 API 容器中使用 CORS,以降低跨域 HTTP 请求所带来的风险
     * @return
     */
   /* @Bean
    public CorsFilter corsFilter() {
        final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        final CorsConfiguration config = new CorsConfiguration();
        config.setAllowCredentials(true);
        config.addAllowedOrigin("*");
        config.addAllowedHeader("*");
        config.addAllowedMethod("*");
        source.registerCorsConfiguration("/**", config);
        return new CorsFilter(source);
    }*/
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59

2.4 配置ResourceServerConfigurerAdapter

**
 * 资源服务器通过 @EnableResourceServer 注解来开启一个 OAuth2AuthenticationProcessingFilter 类型的过滤器
 * 通过继承 ResourceServerConfigurerAdapter 类来配置资源服务器
 */
@Configuration
@EnableResourceServer
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {

	//
    @Bean
    @Qualifier("authorizationHeaderRequestMatcher")
    public RequestMatcher authorizationHeaderRequestMatcher() {
    	//初始化一个名为authorizationHeaderRequestMatcher的匹配器,注入到spring中
        return new RequestHeaderRequestMatcher("Authorization");
    }

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http
                //.requestMatcher(new OAuth2RequestedMatcher())
                .authorizeRequests()
                //接口路径包含“/auth/token"或者“/websocket”的请求,不需要校验token
                .antMatchers("/auth/token", "/websocket").permitAll() //生成 FilterSecurityInterceptor实例(过滤器链中的其中一个过滤器)
                //除了上面指定不需要校验token的请求,其它所有请求都必须校验token
                .anyRequest().authenticated();
        //.antMatchers("/**").hasRole("USER");// 要求接口请求头信息中的token所携带的用户信息中,必须有“USER“角色
    }

    @Override
    public void configure(ResourceServerSecurityConfigurer resources) {

    }

    /**
     * 自定义OAuth2请求匹配器
     */
 /*   private static class OAuth2RequestedMatcher implements RequestMatcher {
        @Override
        public boolean matches(HttpServletRequest request) {
            String auth = request.getHeader("Authorization");
            //判断来源请求是否包含oauth2授权信息,这里授权信息来源可能是头部的Authorization值以Bearer开头,或者是请求参数中包含access_token参数,满足其中一个则匹配成功
            boolean haveOauth2Token = (auth != null) && auth.startsWith("Bearer");
            boolean haveAccessToken = request.getParameter("access_token")!=null;
            return haveOauth2Token || haveAccessToken;
        }
    }*/
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48

如果文章内容有误,或者有更好的理解,欢迎交流,谢谢!

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/不正经/article/detail/84393
推荐阅读
相关标签
  

闽ICP备14008679号