一. IDEA 新建module(我是在原有的项目里面建的,因此创建module就行):oauth2,然后在pom文件中引入资源:
<!-- springboot 的版本 -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.0.RELEASE</version>
<relativePath/>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.security.oauth</groupId>
<artifactId>spring-security-oauth2</artifactId>
<version>2.3.8.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.62</version>
</dependency>
<!-- Lombok 以及需要引入的依赖-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.6</version>
</dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-core</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>javax.activation</groupId>
<artifactId>activation</artifactId>
<version>1.1.1</version>
</dependency>
二. 创建公共实体及工具
- MD5加密工具:
/* * To change this template, choose Tools | Templates * and open the template in the editor. */ package com.cn.oauth.util; import java.math.BigDecimal; import java.math.BigInteger; public class HexUtils { static BigDecimal zero = new BigDecimal(0); /** * 16进制转10进制 * * @param hex * @return */ public static BigInteger hex2Integer(String hex) { if (hex.length() > 2) { if (hex.charAt('0') == 0 && (hex.charAt('x') == 1 || hex.charAt('X') == 1)) { hex = hex.substring(2); } return new BigInteger(hex, 16); } return zero.toBigInteger(); } public static byte[] toHex(byte[] digestByte) { byte[] rtChar = new byte[digestByte.length * 2]; for (int i = 0; i < digestByte.length; i++) { byte b1 = (byte) (digestByte[i] >> 4 & 0x0f); byte b2 = (byte) (digestByte[i] & 0x0f); rtChar[i * 2] = (byte) (b1 < 10 ? b1 + 48 : b1 + 55); rtChar[i * 2 + 1] = (byte) (b2 < 10 ? b2 + 48 : b2 + 55); } return rtChar; } public static String toHexString(byte[] digestByte) { return new String(toHex(digestByte)); } public static byte[] fromHex(byte[] sc) { byte[] res = new byte[sc.length / 2]; for (int i = 0; i < sc.length; i++) { byte c1 = (byte) (sc[i] - 48 < 17 ? sc[i] - 48 : sc[i] - 55); i++; byte c2 = (byte) (sc[i] - 48 < 17 ? sc[i] - 48 : sc[i] - 55); res[i / 2] = (byte) (c1 * 16 + c2); } return res; } public static byte[] fromHexString(String hex) { return fromHex(hex.getBytes()); } public static String encode(String in) { return new String(toHex(in.getBytes())); } public static String decode(String in) { return new String(fromHex(in.getBytes())); } } package com.cn.oauth.util; import java.security.MessageDigest; /** * description: MD5Util <br> * date: 2021/5/18 15:52 <br> * author: cn_yaojin <br> * version: 1.0 <br> */ public class MD5Util { private static String byteArrayToHexString(byte b[]) { StringBuffer resultSb = new StringBuffer(); for (int i = 0; i < b.length; i++) resultSb.append(byteToHexString(b[i])); return resultSb.toString(); } private static String byteToHexString(byte b) { int n = b; if (n < 0) n += 256; int d1 = n / 16; int d2 = n % 16; return hexDigits[d1] + hexDigits[d2]; } public static String MD5Encode(String origin, String charsetname) { String resultString = null; try { resultString = new String(origin); MessageDigest md = MessageDigest.getInstance("MD5"); if (charsetname == null || "".equals(charsetname)) resultString = byteArrayToHexString(md.digest(resultString .getBytes())); else resultString = byteArrayToHexString(md.digest(resultString .getBytes(charsetname))); } catch (Exception exception) { } return resultString; } private static final String hexDigits[] = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f"}; public static String getStringMD5(String s) { try { if (s == null || "".equals(s.trim())) return s; byte[] bytes = s.getBytes("UTF-8"); MessageDigest md = MessageDigest.getInstance("MD5"); md.update(bytes); bytes = md.digest(); String hexString = HexUtils.toHexString(bytes); return hexString; } catch (Exception e) { return null; } } }
2. 创建实体
package com.cn.oauth.entity; import lombok.Getter; import lombok.Setter; import lombok.ToString; import lombok.experimental.Accessors; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.userdetails.User; import javax.naming.Name; import java.util.Collection; /** * description: UserInfo <br> * date: 2021/5/18 15:49 <br> * author: cn_yaojin <br> * version: 1.0 <br> */ @Setter @Getter @Accessors(chain = true) @ToString public class UserInfo extends User { /** * 以下可认为是扩展字段,比如用户年龄、性别、公司、头像 等等都可以放进去 */ private String id; private String name; private String companyId; private String desc = ""; public UserInfo(String username, String password, String id, String desc, Collection<? extends GrantedAuthority> authorities) { super(username, password, authorities); this.id = id; this.name = username; this.companyId = "c_1"; this.desc = desc; } } package com.cn.oauth.entity; import lombok.Getter; import lombok.Setter; import lombok.ToString; import lombok.experimental.Accessors; import java.io.Serializable; /** * description: ClUser <br> * date: 2021/5/18 15:48 <br> * author: cn_yaojin <br> * version: 1.0 <br> */ @Setter @Getter @Accessors(chain = true) @ToString public class ClUser implements Serializable { private static final long serialVersionUID = -7797183521247423117L; private Integer id; private String userName; private String password; }
3. 用户信息查询服务
package com.cn.oauth.service; import com.cn.oauth.entity.ClUser; import com.cn.oauth.entity.UserInfo; import com.cn.oauth.util.MD5Util; import org.apache.commons.lang3.StringUtils; import org.springframework.security.core.authority.AuthorityUtils; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.stereotype.Service; import java.util.ArrayList; import java.util.List; /** * description: UserDetailsServiceImpl <br> * date: 2021/5/18 15:46 <br> * author: cn_yaojin <br> * version: 1.0 <br> */ @Service("userDetailsServiceImpl") public class UserDetailsServiceImpl implements UserDetailsService { @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { System.out.println(">>>>同志们,我的测试:" + username); // 根据名称去查数据库,我为了方便,暂时写死的 ClUser clUser = new ClUser(); clUser.setUserName(username); clUser.setPassword("123456"); // 权限列表 List<String> user_permission = new ArrayList<>(); user_permission.add("admin"); String user_permission_string = StringUtils.join(user_permission.toArray(), ","); return new UserInfo(username, MD5Util.getStringMD5(clUser.getPassword()), "1", "哈哈,测试描述", AuthorityUtils.commaSeparatedStringToAuthorityList(user_permission_string)); } }
4. 目录结构如下:
三. 创建认证服务
- 创建module,名字为:oauth-service
- 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 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>oauth2</artifactId> <groupId>com.cn</groupId> <version>1.0.0</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>oauth-service</artifactId> <dependencies> <!--引入签名创建的oauth-common公共模块 --> <dependency> <groupId>com.cn</groupId> <artifactId>oauth-common</artifactId> <version>1.0.0</version> </dependency> <!--引入mybatis--> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.1.3</version> <exclusions> <exclusion> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-logging</artifactId> </exclusion> </exclusions> </dependency> <!--mysql驱动jar--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.45</version> </dependency> </dependencies> </project>
3. 创建application.yml文件,内容如下,主要有redis、mysql 地址等信息:
server: port: 10090 spring: redis: host: 127.0.0.1 port: 6379 password: database: 0 datasource: url: jdbc:mysql://127.0.0.1:3306/oauth2?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&zeroDateTimeBehavior=convertToNull driver-class-name: com.mysql.jdbc.Driver username: root password: root
4. 创建启动类:OAuthServiceApplication
package com.cn; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; /** * description: OAuthServiceApplication <br> * date: 2021/5/18 16:28 <br> * author: cn_yaojin <br> * version: 1.0 <br> */ @SpringBootApplication public class OAuthServiceApplication { public static void main(String[] args) { SpringApplication.run(OAuthServiceApplication.class, args); System.out.println("服务已启动"); } }
5. 创建 SecurityConfig
package com.cn.config; import com.cn.oauth.util.MD5Util; 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.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.crypto.password.PasswordEncoder; /** * description: SecurityConfig <br> * date: 2021/5/18 15:44 <br> * author: cn_yaojin <br> * version: 1.0 <br> */ @Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { /** * 用户信息查询服务(本示例中,已经在oauth-common 模块中创建好了) */ @Autowired @Qualifier("userDetailsServiceImpl") private UserDetailsService userDetailsService; @Bean(name = "authenticationManagerBean") @Override public AuthenticationManager authenticationManagerBean() throws Exception { return super.authenticationManagerBean(); } @Override protected void configure(HttpSecurity http) throws Exception { http.httpBasic().and().authorizeRequests() .antMatchers("/oauth/**", "/login/**") .permitAll() .anyRequest() .authenticated() .and().csrf().disable(); } @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(userDetailsService); super.configure(auth); } @Bean public PasswordEncoder passwordEncoder() { return new PasswordEncoder() { @Override public String encode(CharSequence charSequence) { return MD5Util.getStringMD5(String.valueOf(charSequence)); } @Override public boolean matches(CharSequence charSequence, String s) { return s.equals(MD5Util.getStringMD5(String.valueOf(charSequence))); } }; } }
6. 创建 AuthorizationConfig
package com.cn.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.context.annotation.Primary; import org.springframework.data.redis.connection.RedisConnectionFactory; 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.ClientDetailsService; 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.TokenStore; import org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStore; import javax.sql.DataSource; /** * description: AuthorizationConfig <br> * date: 2021/5/18 15:43 <br> * author: cn_yaojin <br> * version: 1.0 <br> */ @Configuration @EnableAuthorizationServer public class AuthorizationConfig extends AuthorizationServerConfigurerAdapter { /** * redis工厂,默认使用lettue */ @Autowired public RedisConnectionFactory redisConnectionFactory; /** * 用户认证管理器 */ @Autowired @Qualifier("authenticationManagerBean") public AuthenticationManager authenticationManager; @Autowired private DataSource dataSource; /** * 用户信息查询服务(本示例中,已经在oauth-common 模块中创建好了) */ @Autowired @Qualifier("userDetailsServiceImpl") private UserDetailsService userDetailsService; @Autowired private PasswordEncoder passwordEncoder; /** * 临时授权码存储 * * @return */ @Bean public AuthorizationCodeServices authorizationCodeServices() { return new JdbcAuthorizationCodeServices(dataSource); } @Bean public ClientDetailsService clientDetails() { var jdbcClientDetail = new JdbcClientDetailsService(dataSource); jdbcClientDetail.setPasswordEncoder(passwordEncoder); return jdbcClientDetail; } @Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception { clients.withClientDetails(clientDetails()); } @Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { //配置认证管理器 endpoints.authenticationManager(authenticationManager) //配置用户服务 .userDetailsService(userDetailsService) //配置token存储的服务与位置 .tokenServices(tokenService()) //授权码存储(暂时存储在数据库中,可以优化存储到redis中) .authorizationCodeServices(authorizationCodeServices()) .tokenStore(tokenStore()); } @Override public void configure(AuthorizationServerSecurityConfigurer security) { // 表示支持 client_id 和 client_secret 做登录认证 security.allowFormAuthenticationForClients(); } @Bean public TokenStore tokenStore() { //使用redis存储token RedisTokenStore redisTokenStore = new RedisTokenStore(redisConnectionFactory); //设置redis token存储中的前缀 redisTokenStore.setPrefix("auth-token:"); return redisTokenStore; } @Bean @Primary public DefaultTokenServices tokenService() { DefaultTokenServices tokenServices = new DefaultTokenServices(); //配置token存储 tokenServices.setTokenStore(tokenStore()); //开启支持refresh_token,此处如果之前没有配置,启动服务后再配置重启服务,可能会导致不返回token的问题,解决方式:清除redis对应token存储 tokenServices.setSupportRefreshToken(true); //复用refresh_token tokenServices.setReuseRefreshToken(true); //token有效期,设置12小时 tokenServices.setAccessTokenValiditySeconds(12 * 60 * 60); //refresh_token有效期,设置一周 tokenServices.setRefreshTokenValiditySeconds(7 * 24 * 60 * 60); return tokenServices; } }
7. 此时文件目录如下(图中oauth2目录不用管,那个是扩展):
8. 创建表结构:
SET NAMES utf8mb4; SET FOREIGN_KEY_CHECKS = 0; -- ---------------------------- -- Table structure for oauth_access_token -- ---------------------------- DROP TABLE IF EXISTS `oauth_access_token`; CREATE TABLE `oauth_access_token` ( `create_time` timestamp(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0), `token_id` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, `token` blob NULL, `authentication_id` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, `user_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, `client_id` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, `authentication` blob NULL, `refresh_token` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, INDEX `token_id_index`(`token_id`) USING BTREE, INDEX `authentication_id_index`(`authentication_id`) USING BTREE, INDEX `user_name_index`(`user_name`) USING BTREE, INDEX `client_id_index`(`client_id`) USING BTREE, INDEX `refresh_token_index`(`refresh_token`) USING BTREE ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; -- ---------------------------- -- Table structure for oauth_client_details -- ---------------------------- DROP TABLE IF EXISTS `oauth_client_details`; CREATE TABLE `oauth_client_details` ( `client_id` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, `resource_ids` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, `client_secret` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, `scope` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, `authorized_grant_types` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, `web_server_redirect_uri` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, `authorities` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, `access_token_validity` int(11) NULL DEFAULT NULL, `refresh_token_validity` int(11) NULL DEFAULT NULL, `additional_information` text CHARACTER SET utf8 COLLATE utf8_general_ci NULL, `create_time` timestamp(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0), `archived` tinyint(1) NULL DEFAULT 0, `trusted` tinyint(1) NULL DEFAULT 0, `autoapprove` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT 'false', PRIMARY KEY (`client_id`) USING BTREE ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; -- ---------------------------- -- Records of oauth_client_details -- ---------------------------- INSERT INTO `oauth_client_details` VALUES ('123', '1', 'E10ADC3949BA59ABBE56E057F20F883E', 'read,write,trust', 'authorization_code,password,refresh_token,implicit,client_credentials', 'https://www.baidu.com', NULL, 300, 300, NULL, '2021-05-19 09:24:12', 0, 0, 'false'); -- ---------------------------- -- Table structure for oauth_code -- ---------------------------- DROP TABLE IF EXISTS `oauth_code`; CREATE TABLE `oauth_code` ( `create_time` timestamp(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0), `code` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, `authentication` blob NULL, INDEX `code_index`(`code`) USING BTREE ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; -- ---------------------------- -- Table structure for oauth_refresh_token -- ---------------------------- DROP TABLE IF EXISTS `oauth_refresh_token`; CREATE TABLE `oauth_refresh_token` ( `create_time` timestamp(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0), `token_id` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, `token` blob NULL, `authentication` blob NULL, INDEX `token_id_index`(`token_id`) USING BTREE ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; SET FOREIGN_KEY_CHECKS = 1;
9. 运行项目:
10. 测试秘密模式获取token:
以上请求中,client_id、client_secret、redirect_uri 等参数已经预先在 oauth_client_details 表中创建好了,其中在数据库中 client_secret 是md5加密后的值。例如本示例 client_secret=123456,它在数据库表oauth_client_details 的值为:E10ADC3949BA59ABBE56E057F20F883E。username、 password 本示例已经在 oauth-common模块中的 UserDetailsServiceImpl 中写成死的了。如图:
如图:
postman执行后的结果如下:
11. 授权模式测试:
- get请求获取code:http://localhost:10090/oauth/authorize?client_id=123&response_type=code&scope=trust&redirect_uri=https://www.baidu.com
- 以上步骤中 redirect_uri 要与 数据库表 oauth_client_details 中的 redirect_uri 保持一致
- post请求获取token: http://127.0.0.1:10090/oauth/token?client_id=123&client_secret=123456&grant_type=authorization_code&code=966FEF&redirect_uri=https://www.baidu.com
- 以上步骤中的code 是第一步获取的code值
- redirect_uri 要与 数据库表 oauth_client_details 中的 redirect_uri 保持一致
四. 创建资源服务 module: oauth-resources
-
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 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>oauth2</artifactId> <groupId>com.cn</groupId> <version>1.0.0</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>oauth-resources</artifactId> <dependencies> <dependency> <groupId>com.cn</groupId> <artifactId>oauth-common</artifactId> <version>1.0.0</version> </dependency> </dependencies> </project>
- 创建 application.yml 文件
server: port: 10091 spring: redis: host: 127.0.0.1 port: 6379 password: database: 0
- 创建启动类:OAuthResourcesApplication
package com.cn; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; /** * description: OAuthResourcesApplication <br> * date: 2021/5/18 16:28 <br> * author: cn_yaojin <br> * version: 1.0 <br> */ @SpringBootApplication public class OAuthResourcesApplication { public static void main(String[] args) { SpringApplication.run(OAuthResourcesApplication.class, args); System.out.println("服务已启动"); } }
- 创建资源服务:ResourceServerConfig
package com.cn.config; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.connection.RedisConnectionFactory; 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.store.redis.RedisTokenStore; /** * description: ResourceServerConfig <br> * date: 2021/5/18 16:17 <br> * author: cn_yaojin <br> * version: 1.0 <br> */ @Configuration @EnableResourceServer public class ResourceServerConfig extends ResourceServerConfigurerAdapter { //该属性可以设置成固定的,对应的数据库中 oauth_client_details 表中的resource_ids 保持一致 private final static String RESOURCE_IDS = "1"; @Autowired private RedisConnectionFactory redisConnectionFactory; @Override public void configure(ResourceServerSecurityConfigurer resources) throws Exception { resources.resourceId(RESOURCE_IDS); //无状态 resources.stateless(true); //设置token存储 resources.tokenStore(tokenStore()); } /** * 设置token存储,这一点配置要与授权服务器相一致 */ @Bean public RedisTokenStore tokenStore() { RedisTokenStore redisTokenStore = new RedisTokenStore(redisConnectionFactory); redisTokenStore.setPrefix("auth-token:"); return redisTokenStore; } }
- 创建身份认证服务:SecurityConfig
package com.cn.config; import org.springframework.context.annotation.Configuration; import org.springframework.http.HttpMethod; 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; /** * description: SecurityConfig <br> * date: 2021/5/18 15:44 <br> * author: cn_yaojin <br> * version: 1.0 <br> */ @Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http.csrf().disable() .authorizeRequests()//限定签名成功的请求 .anyRequest().authenticated() .and() .httpBasic(); // http.csrf().disable()//禁用了csrf(跨站请求伪造)功能 // .authorizeRequests()//限定签名成功的请求 // //放行options方法请求 // .antMatchers(HttpMethod.OPTIONS).permitAll() // //必须认证过后才可以访问;注意:hasAnyRole 会默认加上ROLE_前缀,而hasAuthority不会加前缀 // .antMatchers("/demo/**").hasAuthority("user") // 在角色过滤的时候需要注意user角色需要加角色前缀 // .and() // .httpBasic() ; } }
- 创建测试类:
package com.cn.web.demo; import com.alibaba.fastjson.JSON; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; /** * description: DemoController <br> * date: 2021/5/18 16:19 <br> * author: cn_yaojin <br> * version: 1.0 <br> */ @RestController @RequestMapping(value = "demo") public class DemoController { @GetMapping(value = "find") public Object find() { //打印身份信息(从redis中获取的) Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); String txt = JSON.toJSONString(authentication); System.out.println(txt); return authentication; } }
- 资源服务文件目录结构如图:
- 启动资源服务:
- 测试接口:
- 测试url: http://127.0.0.1:10091/demo/find , 测试接口时需要加token,token在 上文认证服务中已经获取到了。
- java 测试代码如下:
public static void main(String[] args) { String url = "http://127.0.0.1:10091/demo/find"; Map<String, String> header = new HashMap<>(); header.put("Authorization", "Bearer 56eb4959-216d-4f83-9beb-31157de7cd12"); String result = HttpUtil2.doGet(url, header); System.out.println(result); }
- 爱上了东风科技