赞
踩
1. 前端发送请求后端进行数据验证(token)整套流程
2.前台调用多个服务原理
3.前台调用单个服务原理
工程目录结构
主要添加了 ResourceServerConfig类,修改了yml配置,新增了pom依赖!之前的工程代码可以参考: SpringCloud微服务–使用使用restTemplate实现服务间调用传参中的服务工程
主类
package com.zhisen.cslcp1;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EnableDiscoveryClient
public class Cslcp1Application {
public static void main(String[] args) {
SpringApplication.run(Cslcp1Application.class, args);
}
}
APPConfig配置类
package com.zhisen.cslcp1.config;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
@Configuration
public class AppConfig {
@Bean
@LoadBalanced
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
ResourceServiceConfig资源服务器配置类
package com.zhisen.cslcp1.config; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; 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.ResourceServerSecurityConfigurer; import org.springframework.security.oauth2.provider.token.RemoteTokenServices; @Configuration @EnableResourceServer // 本服务是一个资源服务器 public class ResourceServerConfig extends ResourceServerConfigurerAdapter { @Value("${security.oauth2.client.client-id}") private String clientId; @Value("${security.oauth2.client.client-secret}") private String secret; @Value("${security.oauth2.authorization.check-token-access}") private String checkTokenEndpointUrl; // 自己这台服务的授权模式 @Override public void configure(HttpSecurity http) throws Exception { http.csrf().disable(); http.authorizeRequests().antMatchers("/test/**").authenticated().antMatchers("/account/**") .hasAuthority("admin"); } // 连接远程服务 @Bean public RemoteTokenServices tokenService() { RemoteTokenServices tokenService = new RemoteTokenServices(); tokenService.setClientId(clientId); tokenService.setClientSecret(secret); tokenService.setCheckTokenEndpointUrl(checkTokenEndpointUrl); return tokenService; } @Override public void configure(ResourceServerSecurityConfigurer resources) throws Exception { resources.tokenServices(tokenService()); } }
接口类根据自己的业务决定
yml
server: port: 10002 spring: application: name: cslcp rabbitmq: host: 172.16.122.112 port: 11223 username: yaohegui password: 123456 datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://172.16.122.112:3306/orders?serverTimezone=GMT%2B8&allowMultiQueries=true&characterEncoding=UTF-8 username: root password: root #mvc: #static-path-pattern: "/static/**" #mybatis: #mapper-locations: com/zhisen/cslcp/dao/*Mapper.xml #type-aliases-package: com.zhisen.cslcp.dao.entity logging: level: com.zhisen.cslcp.dao: debug eureka: instance: hostname: 172.16.122.38 prefer-ip: false #强制使用host指定的ip lease-renewal-interval-in-seconds: 4 lease-expiration-duration-in-seconds: 12 client: hostname: 172.16.122.38 fetch-registry: true registry-fetch-interval-seconds: 8 serviceUrl: defaultZone: http://172.16.122.38:10001/eureka/ security: oauth2: client: client-id: user-client client-secret: user-secret-8888 user-authorization-uri: http://localhost:18889/oauth/authorize access-token-uri: http://localhost:18889/oauth/token resource: id: user-client user-info-uri: user-info authorization: check-token-access: http://localhost:18889/oauth/check_token
pom
引入权限依赖
<!-- 权限依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-oauth2</artifactId>
<version>2.2.5.RELEASE</version>
</dependency>
全:
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.5.1</version> <relativePath /> <!-- lookup parent from repository --> </parent> <groupId>com.zhisen</groupId> <artifactId>cslcp-1</artifactId> <version>0.0.1-SNAPSHOT</version> <name>cslcp-1</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> <spring-cloud.version>2020.0.3</spring-cloud.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> <optional>true</optional> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.76</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-amqp</artifactId> <version>2.0.4.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <!-- 权限依赖 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-oauth2</artifactId> <version>2.2.5.RELEASE</version> </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> </plugin> </plugins> <resources> <resource> <directory>src/main/resources</directory> <includes> <include>**/*.xml</include> <include>**/*.yml</include> </includes> <filtering>false</filtering> </resource> <resource> <directory>src/main/java</directory> <includes> <include>**/*.xml</include> </includes> <filtering>false</filtering> </resource> </resources> </build> </project>
主类
package com.zhisen.uud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EnableDiscoveryClient
public class UudApplication {
public static void main(String[] args) {
SpringApplication.run(UudApplication.class, args);
}
}
APPConfig类
package com.zhisen.uud.config; import javax.sql.DataSource; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.oauth2.provider.token.TokenStore; import org.springframework.security.oauth2.provider.token.store.JdbcTokenStore; @Configuration public class AppConfig { // yml配置的dataSource @Autowired private DataSource dataSource; // 加密密码 @Bean public PasswordEncoder getPasswordEncoder(){ //传说两次加密同一个代码的出的结果不一样 return new BCryptPasswordEncoder(); } // 存储生成token @Bean public TokenStore tokenStore(){ return new JdbcTokenStore(dataSource); } }
OAuth2Config类
package com.zhisen.uud.config; import javax.sql.DataSource; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.crypto.password.PasswordEncoder; 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.configurers.AuthorizationServerEndpointsConfigurer; import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer; import org.springframework.security.oauth2.provider.token.TokenStore; @Configuration //启用认证服务中心 @EnableAuthorizationServer public class OAuth2Config extends AuthorizationServerConfigurerAdapter{ // 当你需要把token存储到数据库中需要注入此bean @Autowired private DataSource dataSource; // 加密需要注入的bean @Autowired public PasswordEncoder passwordEncoder; // 定义的实现类 @Autowired private UserDetailsService userDetailsService; // 认证中心 @Autowired private AuthenticationManager authenticationManager; // token要存储到哪里 @Autowired private TokenStore tokenStore; // 配置认证中心 @Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { // TODO Auto-generated method stub // 将注入的bean都传入进去 endpoints.authenticationManager(authenticationManager).userDetailsService(userDetailsService).tokenStore(tokenStore); } // 配置每一个客户端的认证规则的。(不是授权问题,控制四个接口) @Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception { // TODO Auto-generated method stub /* * JdbcClientDetailsServiceBuilder jdbcBuilder = clients.jdbc(dataSource); * jdbcBuilder.passwordEncoder(passwordEncoder); */ clients.inMemory() // 配置哪一个客户端 .withClient("user-client") // 客户端的登录密码 .secret(passwordEncoder.encode("user-secret-8888")) // 当前客户端允许几种认证模式 /* * refresh_token 刷新token * client_credentials 客户端登录模式 * password 用户密码登录模式 */ .authorizedGrantTypes("refresh_token","client_credentials","password") // token 有效时间 秒为单位 .accessTokenValiditySeconds(3600) // 刷新token时长 一定要比有效时长长 .refreshTokenValiditySeconds(3600) // 全局生效 .scopes("all"); } @Override public void configure(AuthorizationServerSecurityConfigurer security) throws Exception { // TODO Auto-generated method stub // security.allowFormAuthenticationForClients(); // 允许checkToken刷新时开放 security.checkTokenAccess("permitAll()"); // 允许token刷新时开放 security.tokenKeyAccess("permitAll()"); } }
WebSecurityConfig类
授权管理方面只做了简单的设置,详细配置可看: SpringSecurity在单体工程下实现简单登录验证 中的相同名称类。
package com.zhisen.uud.config; import org.springframework.beans.factory.annotation.Autowired; 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.web.builders.HttpSecurity; 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.web.AuthenticationEntryPoint; import org.springframework.security.web.access.AccessDeniedHandler; import org.springframework.security.web.authentication.AuthenticationFailureHandler; import org.springframework.security.web.authentication.AuthenticationSuccessHandler; import org.springframework.security.web.authentication.logout.LogoutSuccessHandler; @Configuration @EnableWebSecurity public class WebSecurityConfig extends WebSecurityConfigurerAdapter{ @Autowired private UserDetailsService userDetailsService; // 认证管理器,security,负责管理认证,能不能登录。 @Bean public AuthenticationManager authenticationManager() throws Exception{ return super.authenticationManager(); } // 初始化认证管理器 @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { // TODO Auto-generated method stub // 指定使用自己定的类来加载 auth.userDetailsService(userDetailsService); } /* * 授权管理 */ @Override protected void configure(HttpSecurity http) throws Exception { // 解决跨域问题 http.csrf().disable(); http.formLogin().permitAll() .and() .authorizeRequests() // 注释掉的这句话意味着只要访问 / 下面的接口全部都可以访问 .antMatchers("/*").permitAll() .and() .logout().permitAll() // 清除缓存 .deleteCookies("JSESSIONID"); } }
认证管理调用的所有方法详情请点击下方链接
SpringSecurity在单体工程下实现简单登录验证
UserDetailServiceImpl类
package com.zhisen.uud.service.impl; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; import com.zhisen.uud.dao.entity.Account; @Service //只负责提供信息,不负责验证 public class UserDetailServiceImpl implements UserDetailsService{ @Autowired PasswordEncoder passwordEncoder; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { if (!"admin".equals(username)) { throw new UsernameNotFoundException(username); } //TODO:使用username参数到后台查询用户信息,使用username参数到数据库查询权限信息 Account account = new Account(); account.setId(0); // admin 是数据库中正式存在的一个账号(登录名称) account.setUserName("admin"); // 加密过程在后续连接数据库后应该取消 account.setPassword(this.passwordEncoder.encode("123456")); // 该列表应该从数据库查询出来 List<String> permisons = new ArrayList<String>(); permisons.add("orede_search"); permisons.add("ROLE_a"); // 如果名称不存在,应该抛出异常 UsernameNotFoundException for (String permisonsStr : permisons) { GrantedAuthority grantedAuthority = new SimpleGrantedAuthority(permisonsStr); account.getAuthorities().add(grantedAuthority); } return account; } }
yml
server: port: 18889 spring: application: name: UAA datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://172.16.122.100:3306/orders?serverTimezone=GMT%2B8&allowMultiQueries=true&characterEncoding=UTF-8 username: root password: root eureka: instance: hostname: 172.16.122.38 prefer-ip: false #强制使用host指定的ip lease-renewal-interval-in-seconds: 4 lease-expiration-duration-in-seconds: 12 client: hostname: 172.16.122.38 fetch-registry: true registry-fetch-interval-seconds: 8 serviceUrl: defaultZone: http://172.16.122.38:10001/eureka/
pom
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.5.1</version> <relativePath /> <!-- lookup parent from repository --> </parent> <groupId>com.zhisen</groupId> <artifactId>cslcp-security</artifactId> <version>0.0.1-SNAPSHOT</version> <name>cslcp-security</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> <spring-cloud.version>2020.0.3</spring-cloud.version> </properties> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-oauth2</artifactId> <version>2.2.5.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </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> </plugin> </plugins> </build> </project>
gateway参考 Spring Cloud gateway的使用
S工程参考 SpringCloud微服务–使用使用restTemplate实现服务间调用传参中的S工程
获取token的接口
客户端认证端口:
刷新token接口
检验token是否有效接口
测试调用接口携带token
create table oauth_client_details ( client_id VARCHAR(256) PRIMARY KEY, resource_ids VARCHAR(256), client_secret VARCHAR(256), scope VARCHAR(256), authorized_grant_types VARCHAR(256), web_server_redirect_uri VARCHAR(256), authorities VARCHAR(256), access_token_validity INTEGER, refresh_token_validity INTEGER, additional_information VARCHAR(4096), autoapprove VARCHAR(256) ); INSERT INTO oauth_client_details (client_id, client_secret, scope, authorized_grant_types, web_server_redirect_uri, authorities, access_token_validity, refresh_token_validity, additional_information, autoapprove) VALUES ('user-client', '$2a$10$o2l5kA7z.Caekp72h5kU7uqdTDrlamLq.57M1F6ulJln9tRtOJufq', 'all', 'refresh_token,password', null, null, 3600, 36000, null, true); INSERT INTO oauth_client_details (client_id, client_secret, scope, authorized_grant_types, web_server_redirect_uri, authorities, access_token_validity, refresh_token_validity, additional_information, autoapprove) VALUES ('order-client', '$2a$10$GoIOhjqFKVyrabUNcie8d.ADX.qZSxpYbO6YK4L2gsNzlCIxEUDlW', 'all', 'refresh_token,password', null, null, 3600, 36000, null, true); create table oauth_access_token ( token_id VARCHAR(128), token BLOB, authentication_id VARCHAR(128) PRIMARY KEY, user_name VARCHAR(128), client_id VARCHAR(128), authentication BLOB, refresh_token VARCHAR(128) ); create table oauth_client_token ( token_id VARCHAR(256), token BLOB, authentication_id VARCHAR(256) PRIMARY KEY, user_name VARCHAR(256), client_id VARCHAR(256) ); create table oauth_refresh_token ( token_id VARCHAR(256), token BLOB, authentication BLOB ); create table oauth_code ( code VARCHAR(256), authentication BLOB ); create table oauth_approvals ( userId VARCHAR(256), clientId VARCHAR(256), scope VARCHAR(256), status VARCHAR(10), expiresAt TIMESTAMP, lastModifiedAt TIMESTAMP ); create table ClientDetails ( appId VARCHAR(256) PRIMARY KEY, resourceIds VARCHAR(256), appSecret VARCHAR(256), scope VARCHAR(256), grantTypes VARCHAR(256), redirectUrl VARCHAR(256), authorities VARCHAR(256), access_token_validity INTEGER, refresh_token_validity INTEGER, additionalInformation VARCHAR(4096), autoApproveScopes VARCHAR(256) );
制作整理不易,以上内容均为原创(参考了部分官方文档和老师整理的案例)。如要引用请附上本文链接,如有疑问可以在评论区畅所欲言,作者看到会第一时间回复,欢迎交流!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。