spring-cloud-2020.0.3-oauth2 + jwt 实现微服务安全认证
1、创建maven基本parent项目

创建一个passport-parent父项目,其中包含了两个模块(module)为passport和account,passport即认证授权的服务,account用来模拟资源服务,将在account服务内部获取到用户的认证授权信息。

  • passport-parent对应的pom.xml文件如下(去除非关键部分)
<project>
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.5.2</version>
        <relativePath/>
    </parent>
    <groupId>com.minxyz.passport</groupId>
    <artifactId>passport-parent</artifactId>
    <version>0.0.1</version>
    <name>passport-parent</name>
    <description>passport-parent project for Spring Boot</description>
    <packaging>pom</packaging>
    <properties>
        <java.version>1.8</java.version>
        <spring-cloud.version>2020.0.3</spring-cloud.version>
    </properties>

    <modules>
        <module>passport</module>
        <module>account</module>
    </modules>
	
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-oauth2</artifactId>
            <version>2.2.5.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-jwt</artifactId>
            <version>1.1.1.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>com.auth0</groupId>
            <artifactId>java-jwt</artifactId>
            <version>3.17.0</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

spring-cloud版本使用2020.0.3,jdk版本使用1.8

2、创建module授权服务器(passport)

即用户登录服务器,类似常见的如passport.jd.com\sso.qq.com

  • 2.1、创建passport项目,其依赖passport-parent父项目(删除非关键信息)

pom.xml配置文件

<project>
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>com.minxyz.passport</groupId>
        <artifactId>passport-parent</artifactId>
        <version>0.0.1</version>
    </parent>
    <groupId>com.minxyz.passport</groupId>
    <artifactId>passport</artifactId>
    <version>0.0.1</version>
    <name>passport</name>
    <description>passport project for Spring Boot</description>

</project>

AuthorizationServerConfig.java 授权服务器配置

@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {

    @Autowired
    private AuthenticationManager authenticationManager;

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints.tokenStore(tokenStore()).accessTokenConverter(accessTokenConverter())
                .authenticationManager(authenticationManager);
    }

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.inMemory().withClient("account").secret("account123").scopes("read", "write")
                .authorizedGrantTypes("password", "authorization_code", "refresh_token");
    }

    @Bean
    public TokenStore tokenStore() {
        return new JwtTokenStore(accessTokenConverter());
    }

    @Bean
    public JwtAccessTokenConverter accessTokenConverter() {
        JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
        converter.setSigningKey("1234567890");
        return converter;
    }

    @Bean
    @Primary
    public DefaultTokenServices tokenServices() {
        DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
        defaultTokenServices.setTokenStore(tokenStore());
        defaultTokenServices.setSupportRefreshToken(true);
        return defaultTokenServices;
    }

}

WebSecurityConfig.java配置文件配置SpringSecurity相关配置

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests().antMatchers("/api/**").permitAll()
                .anyRequest().authenticated();
    }

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication().withUser("admin").password("123456")
                .roles("admin", "user");
    }

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

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new PasswordEncoder() {
            @Override
            public String encode(CharSequence charSequence) {
                return charSequence.toString();
            }

            @Override
            public boolean matches(CharSequence charSequence, String s) {
                return Objects.equals(charSequence.toString(), s);
            }
        };
    }

}

PassportApplication.java 主应用程序入口

@SpringBootApplication
public class PassportApplication {

    public static void main(String[] args) {
        SpringApplication.run(PassportApplication.class, args);
    }

}
  • 2.2、启动应用,获取用户授权token

通过curl -X POST -u account:account123 "http://localhost:8080/oauth/token?grant_type=password&username=admin&password=123456"请求授权服务器,即可获取到用户的token,内容如下

{
    "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.xxx",
    "token_type": "bearer",
    "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.xxx",
    "expires_in": 43199,
    "scope": "read write",
    "jti": "19516ea7-3ac4-4d5a-8bf8-bfb02a027701"
}
字段 说明
access_token 授权token
token_type token类型
refresh_token 刷新token(access_token过期时可使用此token更换)
expires_in token过期时间
scope 授权范围
jti jwt的唯一标识(jwt id)

当access_token快过期时,可使用refresh_token再次更换access_token,注意refresh_token若过期,则需要重新登录验证了 刷新token请求:curl -X POST -u account:account123 -d "grant_type=refresh_token&refresh_token=xxx" localhost:8080/oauth/token

接下来就可以使用这个access_token去访问其他微服务应用(资源服务器)了,在应用中即可获取用户的认证授权信息

3、创建module资源服务器(account)(即对应需要使用到用户认证授权的微服务)
  • 3.1、创建account项目用来模拟微服务获取用户的认证授权信息,其依赖passport-parent父项目(删除非关键信息)

pom.xml配置文件

<project>
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>com.minxyz.passport</groupId>
        <artifactId>passport-parent</artifactId>
        <version>0.0.1</version>
    </parent>
    <groupId>com.minxyz.passport</groupId>
    <artifactId>account</artifactId>
    <version>0.0.1</version>
    <name>account</name>
    <description>account project for Spring Boot</description>
     
</project>

ResourceServerConfig.java

@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {

    @Override
    public void configure(ResourceServerSecurityConfigurer config) {
        config.tokenServices(tokenServices());
    }

    @Bean
    public TokenStore tokenStore() {
        return new JwtTokenStore(accessTokenConverter());
    }

    @Bean
    public JwtAccessTokenConverter accessTokenConverter() {
        JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
        converter.setSigningKey("1234567890"); //需与授权服务器配置的保持一致
        return converter;
    }

    @Bean
    @Primary
    public DefaultTokenServices tokenServices() {
        DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
        defaultTokenServices.setTokenStore(tokenStore());
        defaultTokenServices.setSupportRefreshToken(true);
        return defaultTokenServices;
    }

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/api/**").hasAnyRole("admin")
                .anyRequest().authenticated();
    }

编写一个AccountController.java用来测试

@Slf4j
@RestController
@RequestMapping("/api/account")
public class AccountController {

    @GetMapping("/{id}")
    public String find(@PathVariable("id") String id) {
        log.info(id);
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        log.info("{}", authentication);
        return "success";
    }

}

编写主应用程序

@SpringBootApplication
public class AccountApplication {

    public static void main(String[] args) {
        SpringApplication.run(AccountApplication.class, args);
    }

}
  • 3.2、启动应用,拿到从授权服务器中获取的token请求localhost:8081/api/account/123即可通过

可从gitee中获取 https://gitee.com/viturefree/passport 对应其中的release-1分支代码

4、jwt的token增强功能
  • 4.1、jwt格式

jwt由三部分组成,第一部分为头部(header基本都是一样),第二部分为载荷(payload),第三部分是签名(signature),其中第一、二部分使用Base64编码输出,可以通过Base64完成解码,注意两部分要分开解码获取原始信息。

echo "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9" |base64 --decode
echo "eyJleHAiOjE2MjU2OTY1MzEsInVzZXJfbmFtZSI6ImFkbWluIiwiYXV0aG9yaXRpZXMiOlsiUk9MRV9hZG1pbiIsIlJPTEVfdXNlciJdLCJqdGkiOiIzZmQ2OGQ2NS1jMTNiLTQ2YjYtOGQ3Mi04YTFlYWQ5M2QxZjgiLCJjbGllbnRfaWQiOiJhY2NvdW50Iiwic2NvcGUiOlsicmVhZCIsIndyaXRlIl19" |base64 --decode

源码解析,查看JwtAccessTokenConverter.javaencode方法

protected String encode(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
	String content;
	try {
		content = objectMapper.formatMap(tokenConverter.convertAccessToken(accessToken, authentication));
	}
	catch (Exception e) {
		throw new IllegalStateException("Cannot convert access token to JSON", e);
	}
	String token = JwtHelper.encode(content, signer).getEncoded();
	return token;
}

public static Jwt encode(CharSequence content, Signer signer, Map<String, String> headers) {
    JwtHeader header = JwtHeaderHelper.create(signer, headers);
    byte[] claims = Codecs.utf8Encode(content);
    byte[] crypto = signer.sign(Codecs.concat(new byte[][]{Codecs.b64UrlEncode(header.bytes()), PERIOD, Codecs.b64UrlEncode(claims)}));
    return new JwtImpl(header, claims, crypto);
}

其中的JwtHelper.encode(content, signer).getEncoded();即为将原始content编码后输出,接着拿一个已生成好的access_token分析一下"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJxxx19.TqLBchsqUi_KE2vhadniPz3aAfguaLB7q1PPfkeORrI"(省略部分),access_token按句号分隔成3部分,第一部分解码后为{"alg":"HS256","typ":"JWT"},默认签名算法为HS256,此部分为固定值,第二部分解码后为{"exp":1625696531,"user_name":"admin","authorities":["ROLE_admin","ROLE_user"],"jti":"3fd68d65-c13b-46b6-8d72-8a1ead93d1f8","client_id":"account","scope":["read","write"]}包含有用户名、过期时间及授权信息,第三部分签名根据第一、二部分通过signer.sign生成。

4.2、增强jwt(在jwt中增加自定义信息)

  • passport应用

通常我们需要在jwt中增加一些额外的信息,以便在token中直接获取,从而避免一些接口请求,如用户登录ip,可以通过TokenEnhancer实现。

编写UserTokenEnhancer.java,其主要方法是读取现有的token,再根据方法setAdditionalInformation增加一些额外信息,实际应用中应该获取到用户的一些全局信息放入此字段中,实现如下,

@Component
public class UserTokenEnhancer implements TokenEnhancer {

    @Override
    public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
        if (accessToken instanceof DefaultOAuth2AccessToken) {
            Map<String, Object> additional = new HashMap<>();
            Map<String, Object> param = new HashMap<>();
            param.put("aa","bb");
            param.put("cc","dd");
            additional.put("additional", param);
            ((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(additional);
        }
        return accessToken;
    }

}

修改AuthorizationServerConfig配置,将tokenEnhancer加入到链中

@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
    TokenEnhancerChain chain = new TokenEnhancerChain();
    chain.setTokenEnhancers(Arrays.asList(userTokenEnhancer,accessTokenConverter()));
    endpoints.tokenStore(tokenStore()).tokenEnhancer(chain)
            .authenticationManager(authenticationManager);
}
  • account应用

在account应用中可通过以下的方法获取到用户jwt中的额外信息

Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication instanceof OAuth2Authentication) {
    OAuth2AuthenticationDetails details = (OAuth2AuthenticationDetails) authentication.getDetails();
    OAuth2AccessToken accessToken = new JwtTokenStore(accessTokenConverter).readAccessToken(details.getTokenValue());
    log.info("{}", accessToken.getAdditionalInformation());
}

可从gitee中获取 https://gitee.com/viturefree/passport 对应其中的release/token_enhancer分支代码

5、密码加密功能

前面的passport项目中为了简单起见,使用了内存用户inMemoryAuthentication,并且为明文密码123456,为了更安全我们使用BCryptPasswordEncoder进行加密存储,准确地说是hash算法(不可逆),将计算出的的结果保存。在密码匹配的阶段并不是对密码进行解密,而是使用相同的算法将用户输入的密码进行hash处理,得到新的hash值,再使用matches方法比较两个hash值是否为相同密码。可以执行以下测试代码,结果均为true,s1、s2、s3为不相同密文。

BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
String s1 = encoder.encode("123456");
String s2 = encoder.encode("123456");
String s3= encoder.encode("123456");
System.out.println(s1);
System.out.println(s2);
System.out.println(s3);
System.out.println(encoder.matches("123456",s1));
System.out.println(encoder.matches("123456",s2));
System.out.println(encoder.matches("123456",s3));
  • 应用BCryptPasswordEncoder

依然使用内存用户并将密码encoder改为此类型,代码如下,其中password使用encode方法生成

@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
    auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder()).withUser("admin").password("$2a$10$y2a1hrhZXSDj06tbwaA0bOQCpFAdgOXtt3/T2ml8GUacsPMB.338W")
            .roles("admin", "user");
}

可从gitee中获取 https://gitee.com/viturefree/passport 对应其中的release/bcrypt_password_encoder分支代码

需要注意与PasswordEncoder默认bean不能混淆,因为oauth2对应的client端用户名、密码认证同样使用到此类,所以需保留简单用户名密码的校验方式。

6、修改jwt的access_token及refresh_token有效期并使用数据库存储(jdbc)

默认情况下生成的access_token有效期为24h,refresh_token有效期为30d,可通过以下方式简单设置,将access_token和refresh_token分别设置为1h和12h。

@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
    clients.inMemory().withClient("account").secret("account123").scopes("read", "write")
            .authorizedGrantTypes("password", "authorization_code", "refresh_token")
            .additionalInformation().accessTokenValiditySeconds(3600).refreshTokenValiditySeconds(3600*12);
}
  • 配置使用jdbc的方式存储oauth2的相关配置信息(可以观察到查询语句,此内容为低频修改可使用缓存)

演示使用mysql,建一张表(若只使用到password模式,oauth_client_details表即可),并插入一条测试数据,如下

CREATE TABLE `oauth_client_details` (
  `client_id` varchar(256) NOT NULL,
  `resource_ids` varchar(256) DEFAULT NULL,
  `client_secret` varchar(256) DEFAULT NULL,
  `scope` varchar(256) DEFAULT NULL,
  `authorized_grant_types` varchar(256) DEFAULT NULL,
  `web_server_redirect_uri` varchar(256) DEFAULT NULL,
  `authorities` varchar(256) DEFAULT NULL,
  `access_token_validity` int(11) DEFAULT NULL,
  `refresh_token_validity` int(11) DEFAULT NULL,
  `additional_information` varchar(4096) DEFAULT NULL,
  `autoapprove` varchar(256) DEFAULT NULL,
  PRIMARY KEY (`client_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT INTO `passport`.`oauth_client_details` (`client_id`, `resource_ids`, `client_secret`, `scope`, `authorized_grant_types`, `web_server_redirect_uri`, `authorities`, `access_token_validity`, `refresh_token_validity`, `additional_information`, `autoapprove`) VALUES ('account', '', 'account123', 'read,write', 'password,authorization_code,refresh_token', 'http://www.mixfate.com/user', '', '3600', '7200', '{\"a\":\"c\"}', 'true');

autoapprove为true表示授权码模式时,用户输入用户名及密码后直接跳转到指定页,不需要经过授权确认页完成确认;resource_ids表示允许访问的资源,若为空表示不限制,需与资源服务器的id对应。

将ClientDetailsServiceConfigurer配置修改如下,然后配置好mysql对应的datasource,此时password模式即可正常访问。

@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
    clients.jdbc(dataSource);
}
  • 使用授权码模式完成认证授权

授权码模式需要增加httpBasic()授权认证,调整如下

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.authorizeRequests().antMatchers("/api/**").permitAll()
            .anyRequest().authenticated().and().httpBasic();
}

使用浏览器打开http://127.0.0.1:8080/oauth/authorize?client_id=account&response_type=code&redirect_uri=http://www.mixfate.com/user&state=123456,通过basic验证后(用户名admin,密码123456)即会跳转到redirect_uri页面,并在url后带上code参数,此code即用于换access_token,为了演示方便拿到此code继续请求授权地址localhost:8080/oauth/token?grant_type=authorization_code&code=Btxjsx&redirect_uri=http://www.mixfate.com/user即可获取token,可使用curl测试如下

D:\>curl -i -u admin:123456 "http://127.0.0.1:8080/oauth/authorize?client_id=account&response_type=code&redirect_uri=http://www.mixfate.com/user&state=123456"
HTTP/1.1 302
...
Location: http://www.mixfate.com/user?code=7MAv5W&state=123456
...
D:\>curl -u account:account123 -X POST "http://localhost:8080/oauth/token?grant_type=authorization_code&code=7MAv5W&redirect_uri=http://www.mixfate.com/user"
...

可从gitee中获取 https://gitee.com/viturefree/passport 对应其中的release/auth_database分支代码

7、采用非对称加密算法生成JWT令牌

前面jwt签名算法key使用了固定的1234567890,安全性不高,更好的方式是使用rsa非对称加密算法签名。

  • 如需要获取token对应的key,或校验token key是否正常,增加以下配置允许访问即可,表示允许获取token key和校验token的有效性
@Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
    security.allowFormAuthenticationForClients().tokenKeyAccess("permitAll()").checkTokenAccess("permitAll()");
}

获取token key如:curl -u account:account123 http://localhost:8080/oauth/token_key 校验token 如:curl -X POST -u account:account123 "localhost:8080/oauth/check_token?token=xxx"

  • 使用keytool生成公钥和私钥,并配置到授权服务

生成passport.keystore密钥库

keytool -genkeypair -alias passport -keyalg RSA -dname "CN=Passport,OU=China,O=www.mixfate.com,L=Beijing,S=Beijing,C=China" -keypass s123456 -keystore passport.keystore -storepass s123456 

查看密钥库证书详情,输入证书库密码s123456

keytool -list -keystore passport.keystore

从passport.keystore密钥库中导出公钥(注意需安装openssl),还可直接使用接口查看公钥curl -u account:account123 http://localhost:8080/oauth/token_key,但需配置好passport并启动应用

keytool -list -rfc --keystore passport.keystore | openssl x509 -inform pem -pubkey

将JwtAccessTokenConverter配置修改如下,启动后可用接口获取公钥

@Bean
public JwtAccessTokenConverter accessTokenConverter() {
    JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
    KeyStoreKeyFactory keyStoreKeyFactory = new KeyStoreKeyFactory(new ClassPathResource("passport.keystore"), "s123456".toCharArray());
    converter.setKeyPair(keyStoreKeyFactory.getKeyPair("passport"));
    return converter;
}

如获取的公钥如下

-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlt4nuFdUTYl35h+9dU5t
Oxajub12EGyhmiOavCnHrADTUX2YEjbKqi1yLaXu70wmqfvLjR2tzHcV6rGWSGUS
ThXaPMdlBk6hS8vNOQoUFwVDHdsYoMkyeo6g9B4lmzUBd8y3q1SJDCitJrAf2Nh3
HxQxgCXllJ+YUwrIIx0xCCs4cyAtugxz9p8byPBegcDYhN3+9530O8u3o+7zrYa+
KFiBzLfBORy5KUHxqzy/x//DtWuLf4SLhdZdgfGQj6xI0BE+0vdiyHHPq2inLxhB
V8AMSKkn/CJhxAGg2IDAkfJ/nf24t8vDxzfKXXz0/yXArK6gUAYXNPMzTOZaGgQd
VwIDAQAB
-----END PUBLIC KEY-----
  • 将公钥拷贝到资源服务并完成验证

资源服务account配置文件application.yaml增加配置如下

security:
  oauth2:
    resource:
      jwt:
        key-value: |
          -----BEGIN PUBLIC KEY-----
          MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlt4nuFdUTYl35h+9dU5t
          Oxajub12EGyhmiOavCnHrADTUX2YEjbKqi1yLaXu70wmqfvLjR2tzHcV6rGWSGUS
          ThXaPMdlBk6hS8vNOQoUFwVDHdsYoMkyeo6g9B4lmzUBd8y3q1SJDCitJrAf2Nh3
          HxQxgCXllJ+YUwrIIx0xCCs4cyAtugxz9p8byPBegcDYhN3+9530O8u3o+7zrYa+
          KFiBzLfBORy5KUHxqzy/x//DtWuLf4SLhdZdgfGQj6xI0BE+0vdiyHHPq2inLxhB
          V8AMSKkn/CJhxAGg2IDAkfJ/nf24t8vDxzfKXXz0/yXArK6gUAYXNPMzTOZaGgQd
          VwIDAQAB
          -----END PUBLIC KEY-----

同时注释掉原使用固定signKey的convert注册,改为自动注入即可

@Autowired
private JwtAccessTokenConverter accessTokenConverter;

@Bean
public TokenStore tokenStore() {
    return new JwtTokenStore(accessTokenConverter);
}

可从gitee中获取 https://gitee.com/viturefree/passport 对应其中的release/rsa 分支代码

8、授权服务tokenstore改为使用redis存储
  • 授权服务passport增加redis配置
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
  • AuthorizationServerConfig.java配置文件修改如下
@Autowired
private RedisConnectionFactory connectionFactory;

@Bean
public TokenStore tokenStore() {
    return new RedisTokenStore(connectionFactory);
}
  • application.yaml配置文件增加redis配置
spring:
  redis:
    password: mix2021
    host: 127.0.0.1
    port: 6379

可从gitee中获取 https://gitee.com/viturefree/passport 对应其中的release/redis_token_store分支代码

9、资源服务account配置EnableGlobalMethodSecurity,限制授权访问
  • 增加WebSecurityConfig.java配置
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(jsr250Enabled = true, prePostEnabled = true, securedEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

}
  • AccountController的find方法增加一行配置,同时passport的类WebSecurityConfig配置中roles增加test
@PreAuthorize("hasRole('ROLE_TEST')")

可从gitee中获取 https://gitee.com/viturefree/passport 对应其中的release/enable_global_method_security 分支代码


赞赏(Donation)
微信(Wechat Pay)

donation-wechatpay