update 2021年11月3日18:23:35
parent
5830c7873b
commit
3faa725ec1
|
|
@ -0,0 +1,16 @@
|
|||
package com.zhangmeng.api.service.oauth;
|
||||
|
||||
import com.zhangmeng.model.entity.User;
|
||||
import com.zhangmeng.model.vo.Result;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
|
||||
@Api(tags = "用户授权管理")
|
||||
public interface AuthControllerApi {
|
||||
|
||||
@ApiOperation("令牌解析")
|
||||
public User parseToken();
|
||||
|
||||
@ApiOperation("用户授权")
|
||||
public Result login(String username, String password);
|
||||
}
|
||||
|
|
@ -89,5 +89,15 @@
|
|||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>fastjson</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.jsonwebtoken</groupId>
|
||||
<artifactId>jjwt</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-security</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
package com.zhangmeng.model.entity;
|
||||
|
||||
import com.zhangmeng.model.base.baseEntity.BaseEntity;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Table;
|
||||
|
||||
/**
|
||||
* @author zhengmeng
|
||||
* @version 1.0
|
||||
* @date 2021年1月7日17:44:40
|
||||
*/
|
||||
@NoArgsConstructor
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@Entity
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
@Table(name = "oauth_config")
|
||||
public class OauthConfig extends BaseEntity<Long> {
|
||||
|
||||
private Integer ttl;
|
||||
|
||||
private String clientId;
|
||||
|
||||
private String clientSecret;
|
||||
|
||||
private String cookieDomain;
|
||||
|
||||
private Integer cookieMaxAge;
|
||||
}
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
<?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>mystyle-cloud-parent</artifactId>
|
||||
<groupId>com.zhangmeng</groupId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>mystyle-cloud-oauth</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-amqp</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-sleuth</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-sleuth-zipkin</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-data</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-oauth2</artifactId>
|
||||
<version>2.2.4.RELEASE</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-openfeign</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.zhangmeng</groupId>
|
||||
<artifactId>mystyle-cloud-api</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
</project>
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
package com.zhangmeng.oauth;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
|
||||
import org.springframework.cloud.openfeign.EnableFeignClients;
|
||||
|
||||
/**
|
||||
* @author zhangmeng
|
||||
* @date 2021年11月3日17:00:00
|
||||
* @version 1.0
|
||||
*/
|
||||
@SpringBootApplication
|
||||
@EnableDiscoveryClient
|
||||
@EnableFeignClients
|
||||
public class OauthApplication {
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(OauthApplication.class,args);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,150 @@
|
|||
package com.zhangmeng.oauth.config;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.cloud.bootstrap.encrypt.KeyProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
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.token.DefaultAccessTokenConverter;
|
||||
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;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.sql.DataSource;
|
||||
import java.security.KeyPair;
|
||||
|
||||
/**
|
||||
* @author 转身的背影在心底里沉沦
|
||||
* @date 2021年9月10日09:46:38
|
||||
* @version 1.0
|
||||
*/
|
||||
@Configuration
|
||||
@EnableAuthorizationServer
|
||||
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
|
||||
|
||||
//数据源,用于从数据库获取数据进行认证操作,测试可以从内存中获取
|
||||
@Autowired
|
||||
private DataSource dataSource;
|
||||
|
||||
//jwt令牌转换器
|
||||
@Autowired
|
||||
private JwtAccessTokenConverter jwtAccessTokenConverter;
|
||||
|
||||
//SpringSecurity 用户自定义授权认证类
|
||||
@Qualifier("userDetailsServiceImpl")
|
||||
@Autowired
|
||||
UserDetailsService userDetailsService;
|
||||
|
||||
//授权认证管理器
|
||||
@Autowired
|
||||
AuthenticationManager authenticationManager;
|
||||
|
||||
//令牌持久化存储接口
|
||||
@Autowired
|
||||
TokenStore tokenStore;
|
||||
|
||||
@Resource(name = "keyProp")
|
||||
private KeyProperties keyProperties;
|
||||
|
||||
/***
|
||||
* 客户端信息配置
|
||||
* @param clients
|
||||
* @throws Exception
|
||||
*/
|
||||
@Override
|
||||
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
|
||||
// 动态获取客户端信息
|
||||
clients.jdbc(dataSource) // 加载数据源
|
||||
.clients(clientDetails()); // 查询客户端数据
|
||||
// clients.inMemory() //基于内存
|
||||
// .withClient("mystyle-cloud") //客户端id
|
||||
// .secret("mystyle-cloud") //秘钥
|
||||
// .redirectUris("http://localhost") //重定向地址
|
||||
// .accessTokenValiditySeconds(60) //访问令牌有效期
|
||||
// .refreshTokenValiditySeconds(60) //刷新令牌有效期
|
||||
// .authorizedGrantTypes(
|
||||
// "authorization_code", //根据授权码生成令牌
|
||||
// "client_credentials", //客户端认证
|
||||
// "refresh_token", //刷新令牌
|
||||
// "password") //密码方式认证
|
||||
// .scopes("app"); //客户端范围,名称自定义,必填
|
||||
}
|
||||
|
||||
/***
|
||||
* 授权服务器端点配置
|
||||
* @param endpoints
|
||||
* @throws Exception
|
||||
*/
|
||||
@Override
|
||||
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
|
||||
endpoints.accessTokenConverter(jwtAccessTokenConverter)
|
||||
.authenticationManager(authenticationManager)//认证管理器
|
||||
.tokenStore(tokenStore) //令牌存储
|
||||
.userDetailsService(userDetailsService); //用户信息service
|
||||
}
|
||||
|
||||
/***
|
||||
* 授权服务器的安全配置
|
||||
* @param oauthServer
|
||||
* @throws Exception
|
||||
*/
|
||||
@Override
|
||||
public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
|
||||
oauthServer.allowFormAuthenticationForClients()
|
||||
.passwordEncoder(new BCryptPasswordEncoder())
|
||||
.tokenKeyAccess("permitAll()")
|
||||
.checkTokenAccess("isAuthenticated()");
|
||||
}
|
||||
|
||||
//读取密钥的配置
|
||||
@Bean("keyProp")
|
||||
public KeyProperties keyProperties() {
|
||||
return new KeyProperties();
|
||||
}
|
||||
|
||||
|
||||
//客户端配置
|
||||
@Bean
|
||||
public ClientDetailsService clientDetails() {
|
||||
return new JdbcClientDetailsService(dataSource);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Autowired
|
||||
public TokenStore tokenStore(JwtAccessTokenConverter jwtAccessTokenConverter) {
|
||||
return new JwtTokenStore(jwtAccessTokenConverter);
|
||||
}
|
||||
|
||||
/****
|
||||
* JWT令牌转换器
|
||||
* @param customUserAuthenticationConverter
|
||||
* @return
|
||||
*/
|
||||
@Bean
|
||||
public JwtAccessTokenConverter jwtAccessTokenConverter(CustomUserAuthenticationConverter customUserAuthenticationConverter) {
|
||||
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
|
||||
KeyPair keyPair = new KeyStoreKeyFactory(
|
||||
keyProperties.getKeyStore().getLocation(), //证书路径
|
||||
keyProperties.getKeyStore().getSecret().toCharArray()) //证书秘钥
|
||||
.getKeyPair(
|
||||
keyProperties.getKeyStore().getAlias(), //证书别名
|
||||
keyProperties.getKeyStore().getPassword().toCharArray()); //证书密码
|
||||
converter.setKeyPair(keyPair);
|
||||
//配置自定义的CustomUserAuthenticationConverter
|
||||
DefaultAccessTokenConverter accessTokenConverter = (DefaultAccessTokenConverter) converter.getAccessTokenConverter();
|
||||
accessTokenConverter.setUserTokenConverter(customUserAuthenticationConverter);
|
||||
return converter;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
package com.zhangmeng.oauth.config;
|
||||
|
||||
import com.zhangmeng.oauth.utils.UserJwt;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.security.core.Authentication;
|
||||
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.oauth2.provider.token.DefaultUserAuthenticationConverter;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 自定义用户授权转换
|
||||
*/
|
||||
@Component
|
||||
public class CustomUserAuthenticationConverter extends DefaultUserAuthenticationConverter {
|
||||
|
||||
@Qualifier("userDetailsServiceImpl")
|
||||
@Autowired
|
||||
UserDetailsService userDetailsService;
|
||||
|
||||
@Override
|
||||
public Map<String, ?> convertUserAuthentication(Authentication authentication) {
|
||||
HashMap<String,Object> response = new LinkedHashMap<>();
|
||||
String name = authentication.getName();
|
||||
response.put("username", name);
|
||||
|
||||
Object principal = authentication.getPrincipal();
|
||||
UserJwt userJwt = null;
|
||||
if (principal instanceof UserJwt) {
|
||||
userJwt = (UserJwt) principal;
|
||||
} else {
|
||||
//refresh_token默认不去调用userdetailService获取用户信息,这里我们手动去调用,得到 UserJwt
|
||||
UserDetails userDetails = userDetailsService.loadUserByUsername(name);
|
||||
userJwt = (UserJwt) userDetails;
|
||||
}
|
||||
response.put("name", userJwt.getName());
|
||||
response.put("id", userJwt.getId());
|
||||
if (authentication.getAuthorities() != null && !authentication.getAuthorities().isEmpty()) {
|
||||
response.put("authorities", AuthorityUtils.authorityListToSet(authentication.getAuthorities()));
|
||||
}
|
||||
return response;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
package com.zhangmeng.oauth.config;
|
||||
|
||||
import com.zhangmeng.oauth.utils.JwtToken;
|
||||
import feign.RequestInterceptor;
|
||||
import feign.RequestTemplate;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.context.request.RequestContextHolder;
|
||||
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.Enumeration;
|
||||
|
||||
/**
|
||||
* 请求拦截器
|
||||
*/
|
||||
@Configuration
|
||||
public class FeignOauth2RequestInterceptor implements RequestInterceptor {
|
||||
@Override
|
||||
public void apply(RequestTemplate requestTemplate) {
|
||||
// 获取的全部请求信息
|
||||
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
|
||||
if (attributes != null){
|
||||
HttpServletRequest request = attributes.getRequest();
|
||||
// 获取所有的请求头信息
|
||||
Enumeration<String> headerNames = request.getHeaderNames();
|
||||
if (headerNames != null){
|
||||
while (headerNames.hasMoreElements()){
|
||||
// 获取请求头的key
|
||||
String element = headerNames.nextElement();
|
||||
// 获取请求头的value
|
||||
String value = request.getHeader(element);
|
||||
// 将请求头信息放入到请求头
|
||||
requestTemplate.header(element,value);
|
||||
}
|
||||
}
|
||||
}
|
||||
// 获得带有权限的令牌(将令牌放入请求头中,用于登录到的时候携带权限信息)
|
||||
String token = JwtToken.adminJwt();
|
||||
// 如果微服务之间相互调用,也需要将令牌放入请求头中,
|
||||
requestTemplate.header("Authorization","bearer " + token);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
package com.zhangmeng.oauth.config;
|
||||
|
||||
import com.zhangmeng.domain.admin.Permission;
|
||||
import com.zhangmeng.feign.admin.AdminFeign;
|
||||
import com.zhangmeng.oauth.utils.UserJwt;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.authority.AuthorityUtils;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
import org.springframework.security.core.userdetails.User;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
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.security.oauth2.provider.ClientDetails;
|
||||
import org.springframework.security.oauth2.provider.ClientDetailsService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 自定义授权认证类
|
||||
*
|
||||
* @author 转身的背影在心底里沉沦
|
||||
* @date 2021年9月14日11:54:013
|
||||
* @version 1.0
|
||||
*/
|
||||
@Service
|
||||
public class UserDetailsServiceImpl implements UserDetailsService {
|
||||
|
||||
@Autowired
|
||||
ClientDetailsService clientDetailsService;
|
||||
|
||||
@Autowired
|
||||
PasswordEncoder passwordEncoder;
|
||||
|
||||
@Autowired
|
||||
private AdminFeign adminFeign;
|
||||
|
||||
/****
|
||||
* 自定义授权认证
|
||||
* @param username
|
||||
* @return
|
||||
* @throws UsernameNotFoundException
|
||||
*/
|
||||
@Override
|
||||
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
|
||||
//取出身份,如果身份为空说明没有认证
|
||||
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
||||
//没有认证统一采用httpbasic认证,httpbasic中存储了client_id和client_secret,开始认证client_id和client_secret
|
||||
if(authentication==null){
|
||||
ClientDetails clientDetails = clientDetailsService.loadClientByClientId(username);
|
||||
if(clientDetails!=null){
|
||||
//秘钥
|
||||
String clientSecret = clientDetails.getClientSecret();
|
||||
//静态方式
|
||||
//return new User(username,new BCryptPasswordEncoder().encode(clientSecret), AuthorityUtils.commaSeparatedStringToAuthorityList(""));
|
||||
//数据库查找方式
|
||||
return new User(username,clientSecret, AuthorityUtils.commaSeparatedStringToAuthorityList(""));
|
||||
}
|
||||
}
|
||||
|
||||
if (StringUtils.isEmpty(username)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// 通过数据库去查询用户通过密码授权
|
||||
com.zhangmeng.domain.admin.User user = this.adminFeign.findByUserName(username);
|
||||
|
||||
//根据用户查询权限列表
|
||||
List<Permission> permissions = this.adminFeign.findByUserId(user.getId());
|
||||
Set<SimpleGrantedAuthority> collect = permissions.parallelStream().filter(permission -> !org.springframework.util.StringUtils.isEmpty(permission.getTitle()))
|
||||
.map(permission -> new SimpleGrantedAuthority(permission.getTitle())).collect(Collectors.toSet());
|
||||
return new UserJwt(username,user.getPassword(),collect);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,94 @@
|
|||
package com.zhangmeng.oauth.config;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
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.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.web.servlet.config.annotation.CorsRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
@Order(-1)
|
||||
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
|
||||
|
||||
/***
|
||||
* 采用BCryptPasswordEncoder对密码进行编码
|
||||
* @return
|
||||
*/
|
||||
@Bean
|
||||
public PasswordEncoder passwordEncoder() {
|
||||
return new BCryptPasswordEncoder();
|
||||
}
|
||||
|
||||
/***
|
||||
* 忽略安全拦截的URL
|
||||
* @param web
|
||||
* @throws Exception
|
||||
*/
|
||||
@Override
|
||||
public void configure(WebSecurity web) throws Exception {
|
||||
// 对静态资源放行
|
||||
web.ignoring().antMatchers(
|
||||
"/user/login",
|
||||
"/user/logout",
|
||||
"/oauth/login"
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 跨域支持
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Bean
|
||||
public WebMvcConfigurer corsConfigurer() {
|
||||
return new WebMvcConfigurer() {
|
||||
@Override
|
||||
public void addCorsMappings(CorsRegistry registry) {
|
||||
registry.addMapping("/**").allowedMethods("*");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/***
|
||||
* 创建授权管理认证对象
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
@Bean
|
||||
@Override
|
||||
public AuthenticationManager authenticationManagerBean() throws Exception {
|
||||
return super.authenticationManagerBean();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/****
|
||||
*
|
||||
* @param http
|
||||
* @throws Exception
|
||||
*/
|
||||
@Override
|
||||
public void configure(HttpSecurity http) throws Exception {
|
||||
|
||||
http.csrf().disable()
|
||||
.httpBasic() //启用Http基本身份验证
|
||||
.and()
|
||||
.formLogin() //启用表单身份验证
|
||||
// 自定义登录请求(视图请求)
|
||||
.loginPage("/oauth/login")
|
||||
// springSecurity自带登录地址
|
||||
.loginProcessingUrl("/user/login")
|
||||
.and()
|
||||
.authorizeRequests() //限制基于Request请求访问
|
||||
.anyRequest()
|
||||
.authenticated(); //其他请求都需要经过验证
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,111 @@
|
|||
package com.zhangmeng.oauth.controller;
|
||||
|
||||
import com.alibaba.cloud.commons.lang.StringUtils;
|
||||
import com.zhangmeng.api.service.oauth.AuthControllerApi;
|
||||
import com.zhangmeng.model.base.baseController.BaseController;
|
||||
import com.zhangmeng.model.entity.OauthConfig;
|
||||
import com.zhangmeng.model.entity.User;
|
||||
import com.zhangmeng.model.vo.Result;
|
||||
import com.zhangmeng.model.vo.StatusCode;
|
||||
import com.zhangmeng.oauth.dto.AuthToken;
|
||||
import com.zhangmeng.oauth.feign.AdminFeign;
|
||||
import com.zhangmeng.oauth.service.AuthService;
|
||||
import com.zhangmeng.oauth.service.OauthConfigService;
|
||||
import com.zhangmeng.oauth.utils.CookieUtil;
|
||||
import com.zhangmeng.oauth.utils.TokenTools;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.context.request.RequestContextHolder;
|
||||
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.util.Map;
|
||||
|
||||
@RestController
|
||||
@RequestMapping(value = "/user")
|
||||
public class AuthController extends BaseController implements AuthControllerApi {
|
||||
|
||||
@Autowired
|
||||
private AdminFeign adminFeign;
|
||||
|
||||
@Autowired
|
||||
private OauthConfigService oauthConfigService;
|
||||
|
||||
@Autowired
|
||||
private AuthService authService;
|
||||
|
||||
@Autowired
|
||||
PasswordEncoder passwordEncoder;
|
||||
|
||||
@Autowired
|
||||
private TokenTools tokenTools;
|
||||
|
||||
@Override
|
||||
@GetMapping("/oauth/parseToken")//解析
|
||||
public User parseToken() {
|
||||
Map<String, String> userInfo = this.tokenTools.getUserInfo();
|
||||
String username = userInfo.get("username");
|
||||
return this.adminFeign.findByUserName(username);
|
||||
}
|
||||
|
||||
@Override
|
||||
@PostMapping("/login")
|
||||
public Result login(String username, String password) {
|
||||
if (StringUtils.isEmpty(username)) {
|
||||
throw new RuntimeException("用户名不允许为空");
|
||||
}
|
||||
if (StringUtils.isEmpty(password)) {
|
||||
throw new RuntimeException("密码不允许为空");
|
||||
}
|
||||
User user = this.adminFeign.findByUserName(username);
|
||||
if (user == null){
|
||||
throw new UsernameNotFoundException("用户名错误");
|
||||
}
|
||||
//校验密码是否正确,如果正确则申请令牌
|
||||
if (!this.passwordEncoder.matches(password,user.getPassword())) {
|
||||
throw new RuntimeException("密码错误");
|
||||
}
|
||||
OauthConfig oauthConfig = this.oauthConfig();
|
||||
AuthToken authToken = auth_login(username, password,oauthConfig);
|
||||
//用户身份令牌
|
||||
String access_token = authToken.getAccessToken();
|
||||
//将令牌存储到cookie
|
||||
saveCookie(access_token,oauthConfig);
|
||||
return new Result(true, StatusCode.OK, "登录成功!",authToken);
|
||||
}
|
||||
|
||||
private AuthToken auth_login(String username, String password,OauthConfig oauthConfig){
|
||||
//客户端ID
|
||||
String clientId = oauthConfig.getClientId();
|
||||
//秘钥
|
||||
String clientSecret = oauthConfig.getClientSecret();
|
||||
//申请令牌
|
||||
return this.authService.login(username, password, clientId, clientSecret);
|
||||
}
|
||||
|
||||
private OauthConfig oauthConfig(){
|
||||
OauthConfig oauthConfig = this.oauthConfigService.oauthConfig();
|
||||
if (oauthConfig == null) {
|
||||
throw new RuntimeException("oauthConfig 配置读取错误");
|
||||
}
|
||||
return oauthConfig;
|
||||
}
|
||||
|
||||
/***
|
||||
* 将令牌存储到cookie
|
||||
* @param token
|
||||
*/
|
||||
private void saveCookie(String token,OauthConfig oauthConfig) {
|
||||
//Cookie存储的域名
|
||||
String cookieDomain = oauthConfig.getCookieDomain();
|
||||
//Cookie生命周期
|
||||
int cookieMaxAge = oauthConfig.getCookieMaxAge();
|
||||
HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
|
||||
CookieUtil.addCookie(response, cookieDomain, "/", "Authorization", token, cookieMaxAge, false);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
package com.zhangmeng.oauth.dao;
|
||||
|
||||
|
||||
import com.zhangmeng.model.base.baseDao.AbstractBaseMapper;
|
||||
import com.zhangmeng.model.entity.OauthConfig;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
@Mapper
|
||||
public interface OauthConfigDao extends AbstractBaseMapper<OauthConfig> {
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
package com.zhangmeng.oauth.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@Data
|
||||
public class AuthToken implements Serializable {
|
||||
|
||||
//令牌信息
|
||||
String accessToken;
|
||||
|
||||
//刷新token(refresh_token)
|
||||
String refreshToken;
|
||||
|
||||
//jwt短令牌
|
||||
String jti;
|
||||
}
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
package com.zhangmeng.oauth.dto;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
import org.springframework.security.jwt.Jwt;
|
||||
import org.springframework.security.jwt.JwtHelper;
|
||||
import org.springframework.security.jwt.crypto.sign.RsaSigner;
|
||||
import org.springframework.security.oauth2.provider.token.store.KeyStoreKeyFactory;
|
||||
|
||||
import java.security.KeyPair;
|
||||
import java.security.interfaces.RSAPrivateKey;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author 转身的背影在心底里沉沦
|
||||
* @date 2021年9月18日12:23:40
|
||||
* @version 1.0
|
||||
*/
|
||||
public class JwtToken {
|
||||
public static String adminJwt(){
|
||||
//证书文件路径
|
||||
String key_location="mystyle-cloud.jks";
|
||||
//秘钥库密码
|
||||
String key_password="mystyle-cloud";
|
||||
//秘钥密码
|
||||
String keypwd = "mystyle-cloud";
|
||||
//秘钥别名
|
||||
String alias = "mystyle-cloud";
|
||||
|
||||
//访问证书路径
|
||||
ClassPathResource resource = new ClassPathResource(key_location);
|
||||
|
||||
//创建秘钥工厂
|
||||
KeyStoreKeyFactory keyStoreKeyFactory = new KeyStoreKeyFactory(resource,key_password.toCharArray());
|
||||
|
||||
//读取秘钥对(公钥、私钥)
|
||||
KeyPair keyPair = keyStoreKeyFactory.getKeyPair(alias,keypwd.toCharArray());
|
||||
|
||||
//获取私钥
|
||||
RSAPrivateKey rsaPrivate = (RSAPrivateKey) keyPair.getPrivate();
|
||||
|
||||
//定义Payload9(载荷,给生成的令牌加权限)
|
||||
Map<String, Object> tokenMap = new HashMap<>();
|
||||
// key 就是解析后的authorities, value是权限 信息可以有多个
|
||||
tokenMap.put("authorities", new String[]{"admin"});
|
||||
|
||||
//生成Jwt令牌
|
||||
Jwt jwt = JwtHelper.encode(JSON.toJSONString(tokenMap), new RsaSigner(rsaPrivate));
|
||||
|
||||
//取出令牌
|
||||
return jwt.getEncoded();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
package com.zhangmeng.oauth.dto;
|
||||
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.userdetails.User;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
public class UserJwt extends User {
|
||||
private String id; //用户ID
|
||||
private String name; //用户名字
|
||||
|
||||
public UserJwt(String username, String password, Collection<? extends GrantedAuthority> authorities) {
|
||||
super(username, password, authorities);
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
package com.zhangmeng.oauth.feign;
|
||||
|
||||
import com.zhangmeng.model.entity.User;
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
|
||||
@FeignClient("")
|
||||
public interface AdminFeign {
|
||||
|
||||
@RequestMapping("")
|
||||
User findByUserName(String username);
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
package com.zhangmeng.oauth.service;
|
||||
|
||||
|
||||
import com.zhangmeng.oauth.dto.AuthToken;
|
||||
|
||||
public interface AuthService {
|
||||
|
||||
/***
|
||||
* 授权认证方法
|
||||
*/
|
||||
AuthToken login(String username, String password, String clientId, String clientSecret);
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
package com.zhangmeng.oauth.service;
|
||||
|
||||
|
||||
import com.zhangmeng.model.base.baseService.BaseService;
|
||||
import com.zhangmeng.model.entity.OauthConfig;
|
||||
|
||||
public interface OauthConfigService extends BaseService<OauthConfig> {
|
||||
|
||||
public OauthConfig oauthConfig();
|
||||
}
|
||||
|
|
@ -0,0 +1,130 @@
|
|||
package com.zhangmeng.oauth.service.impl;
|
||||
|
||||
import com.zhangmeng.oauth.dto.AuthToken;
|
||||
import com.zhangmeng.oauth.service.AuthService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.cloud.client.ServiceInstance;
|
||||
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.http.client.ClientHttpResponse;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.Base64Utils;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.web.client.DefaultResponseErrorHandler;
|
||||
import org.springframework.web.client.RestClientException;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
|
||||
@Service
|
||||
public class AuthServiceImpl implements AuthService {
|
||||
|
||||
@Autowired
|
||||
private LoadBalancerClient loadBalancerClient;
|
||||
|
||||
@Autowired
|
||||
private RestTemplate restTemplate;
|
||||
|
||||
/***
|
||||
* 授权认证方法
|
||||
* @param username
|
||||
* @param password
|
||||
* @param clientId
|
||||
* @param clientSecret
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public AuthToken login(String username, String password, String clientId, String clientSecret) {
|
||||
//申请令牌
|
||||
AuthToken authToken = applyToken(username,password,clientId, clientSecret);
|
||||
if(authToken == null){
|
||||
throw new RuntimeException("申请令牌失败");
|
||||
}
|
||||
return authToken;
|
||||
}
|
||||
|
||||
|
||||
/****
|
||||
* 认证方法
|
||||
* @param username:用户登录名字
|
||||
* @param password:用户密码
|
||||
* @param clientId:配置文件中的客户端ID
|
||||
* @param clientSecret:配置文件中的秘钥
|
||||
* @return AuthToken
|
||||
*/
|
||||
private AuthToken applyToken(String username, String password, String clientId, String clientSecret) {
|
||||
//选中认证服务的地址
|
||||
ServiceInstance serviceInstance = loadBalancerClient.choose("mystyle-user-oauth");
|
||||
if (serviceInstance == null) {
|
||||
throw new RuntimeException("找不到对应的服务");
|
||||
}
|
||||
//获取令牌的url
|
||||
String path = serviceInstance.getUri().toString() + "/oauth/token";
|
||||
//定义body
|
||||
MultiValueMap<String, String> formData = new LinkedMultiValueMap<>();
|
||||
//授权方式
|
||||
formData.add("grant_type", "password");
|
||||
//账号
|
||||
formData.add("username", username);
|
||||
//密码
|
||||
formData.add("password", password);
|
||||
//定义头
|
||||
MultiValueMap<String, String> header = new LinkedMultiValueMap<>();
|
||||
header.add("Authorization", httpbasic(clientId, clientSecret));
|
||||
//指定 restTemplate当遇到400或401响应时候也不要抛出异常,也要正常返回值
|
||||
restTemplate.setErrorHandler(new DefaultResponseErrorHandler() {
|
||||
@Override
|
||||
public void handleError(ClientHttpResponse response) throws IOException {
|
||||
//当响应的值为400或401时候也要正常响应,不要抛出异常
|
||||
if (response.getRawStatusCode() != 400 && response.getRawStatusCode() != 401) {
|
||||
super.handleError(response);
|
||||
}
|
||||
}
|
||||
});
|
||||
Map map = null;
|
||||
try {
|
||||
//http请求spring security的申请令牌接口
|
||||
ResponseEntity<Map> mapResponseEntity = restTemplate.exchange(path, HttpMethod.POST,new HttpEntity<MultiValueMap<String, String>>(formData, header), Map.class);
|
||||
//获取响应数据
|
||||
map = mapResponseEntity.getBody();
|
||||
} catch (RestClientException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
if(map == null || map.get("access_token") == null || map.get("refresh_token") == null || map.get("jti") == null) {
|
||||
//jti是jwt令牌的唯一标识作为用户身份令牌
|
||||
throw new RuntimeException("创建令牌失败!");
|
||||
}
|
||||
|
||||
//将响应数据封装成AuthToken对象
|
||||
AuthToken authToken = new AuthToken();
|
||||
//访问令牌(jwt)
|
||||
String accessToken = (String) map.get("access_token");
|
||||
//刷新令牌(jwt)
|
||||
String refreshToken = (String) map.get("refresh_token");
|
||||
//jti,作为用户的身份标识
|
||||
String jwtToken= (String) map.get("jti");
|
||||
authToken.setJti(jwtToken);
|
||||
authToken.setAccessToken(accessToken);
|
||||
authToken.setRefreshToken(refreshToken);
|
||||
return authToken;
|
||||
}
|
||||
|
||||
|
||||
/***
|
||||
* base64编码
|
||||
* @param clientId
|
||||
* @param clientSecret
|
||||
* @return
|
||||
*/
|
||||
private String httpbasic(String clientId,String clientSecret){
|
||||
//将客户端id和客户端密码拼接,按“客户端id:客户端密码”
|
||||
String string = clientId+":"+clientSecret;
|
||||
//进行base64编码
|
||||
byte[] encode = Base64Utils.encode(string.getBytes());
|
||||
return "Basic "+new String(encode);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
package com.zhangmeng.oauth.service.impl;
|
||||
|
||||
import com.zhangmeng.model.base.baseService.impl.AbstractBaseServiceImpl;
|
||||
import com.zhangmeng.model.entity.OauthConfig;
|
||||
import com.zhangmeng.oauth.service.OauthConfigService;
|
||||
import org.springframework.stereotype.Service;
|
||||
import tk.mybatis.mapper.entity.Condition;
|
||||
import tk.mybatis.mapper.entity.Example;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Service
|
||||
public class OauthConfigServiceImpl extends AbstractBaseServiceImpl<OauthConfig> implements OauthConfigService {
|
||||
|
||||
public OauthConfig oauthConfig(){
|
||||
Condition condition = new Condition(OauthConfig.class);
|
||||
Example.Criteria criteria = condition.createCriteria();
|
||||
condition.setOrderByClause("addTime desc");
|
||||
List<OauthConfig> oauthConfigs = this.findByCondition(condition);
|
||||
if (oauthConfigs.size() > 0 ){
|
||||
return oauthConfigs.get(0);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
package com.zhangmeng.oauth.utils;
|
||||
|
||||
import javax.servlet.http.Cookie;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class CookieUtil {
|
||||
|
||||
/**
|
||||
* 设置cookie
|
||||
*
|
||||
* @param response
|
||||
* @param name cookie名字
|
||||
* @param value cookie值
|
||||
* @param maxAge cookie生命周期 以秒为单位
|
||||
*/
|
||||
public static void addCookie(HttpServletResponse response, String domain, String path, String name,
|
||||
String value, int maxAge, boolean httpOnly) {
|
||||
Cookie cookie = new Cookie(name, value);
|
||||
cookie.setDomain(domain);
|
||||
cookie.setPath(path);
|
||||
cookie.setMaxAge(maxAge);
|
||||
cookie.setHttpOnly(httpOnly);
|
||||
response.addCookie(cookie);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据cookie名称读取cookie
|
||||
* @param request
|
||||
* @return map<cookieName,cookieValue>
|
||||
*/
|
||||
|
||||
public static Map<String,String> readCookie(HttpServletRequest request, String ... cookieNames) {
|
||||
Map<String,String> cookieMap = new HashMap<String,String>();
|
||||
Cookie[] cookies = request.getCookies();
|
||||
if (cookies != null) {
|
||||
for (Cookie cookie : cookies) {
|
||||
String cookieName = cookie.getName();
|
||||
String cookieValue = cookie.getValue();
|
||||
for(int i=0;i<cookieNames.length;i++){
|
||||
if(cookieNames[i].equals(cookieName)){
|
||||
cookieMap.put(cookieName,cookieValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return cookieMap;
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
package com.zhangmeng.oauth.utils;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.jwt.Jwt;
|
||||
import org.springframework.security.jwt.JwtHelper;
|
||||
import org.springframework.security.jwt.crypto.sign.RsaVerifier;
|
||||
import org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationDetails;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Component
|
||||
public class TokenTools {
|
||||
|
||||
//公钥
|
||||
private static final String PUBLIC_KEY = "public.key";
|
||||
|
||||
private static String publickey="";
|
||||
|
||||
/***
|
||||
* 获取用户信息
|
||||
* @return
|
||||
*/
|
||||
public Map<String,String> getUserInfo(){
|
||||
//获取授权信息
|
||||
OAuth2AuthenticationDetails details = (OAuth2AuthenticationDetails) SecurityContextHolder.getContext().getAuthentication().getDetails();
|
||||
//令牌解码
|
||||
return dcodeToken(details.getTokenValue());
|
||||
}
|
||||
|
||||
/***
|
||||
* 读取令牌数据
|
||||
*/
|
||||
public Map<String,String> dcodeToken(String token){
|
||||
//校验Jwt
|
||||
Jwt jwt = JwtHelper.decodeAndVerify(token, new RsaVerifier(getPubKey()));
|
||||
//获取Jwt原始内容
|
||||
String claims = jwt.getClaims();
|
||||
return JSON.parseObject(claims,Map.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取非对称加密公钥 Key
|
||||
* @return 公钥 Key
|
||||
*/
|
||||
public String getPubKey() {
|
||||
if(!StringUtils.isEmpty(publickey)){
|
||||
return publickey;
|
||||
}
|
||||
Resource resource = new ClassPathResource(PUBLIC_KEY);
|
||||
try {
|
||||
InputStreamReader inputStreamReader = new InputStreamReader(resource.getInputStream());
|
||||
BufferedReader br = new BufferedReader(inputStreamReader);
|
||||
publickey = br.lines().collect(Collectors.joining("\n"));
|
||||
return publickey;
|
||||
} catch (IOException ioe) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
server:
|
||||
port: 31006
|
||||
spring:
|
||||
application:
|
||||
name: mystyle-cloud-file
|
||||
datasource:
|
||||
username: root
|
||||
password: root
|
||||
url: jdbc:mysql://127.0.0.1:3306/mystyle-blog?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&nullCatalogMeansCurrent=true
|
||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||
jpa:
|
||||
database: mysql
|
||||
hibernate:
|
||||
ddl-auto: update
|
||||
naming:
|
||||
physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
|
||||
show-sql: true
|
||||
properties:
|
||||
hibernate:
|
||||
dialect: org.hibernate.dialect.MySQL5Dialect
|
||||
zipkin:
|
||||
sender:
|
||||
type: web
|
||||
base-url: http://localhost:9411/
|
||||
service:
|
||||
name: mystyle-cloud-file
|
||||
sleuth:
|
||||
sampler:
|
||||
probability: 1
|
||||
cloud:
|
||||
nacos:
|
||||
discovery:
|
||||
server-addr: 127.0.0.1:8848
|
||||
mybatis:
|
||||
type-aliases-package: com.zhangmeng.model.entity
|
||||
configuration:
|
||||
mapUnderscoreToCamelCase: true
|
||||
default-enum-type-handler: org.apache.ibatis.type.EnumOrdinalTypeHandler
|
||||
mapper:
|
||||
style: normal
|
||||
enum-as-simple-type: true
|
||||
identity: MYSQL
|
||||
check-example-entity-class: true
|
||||
Binary file not shown.
|
|
@ -0,0 +1 @@
|
|||
-----BEGIN PUBLIC KEY-----MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAizuj0fBV2+dj4lM3G6efKYvC2czd07BqmzV++E2yBguVks3XWvsW8qlzmG+t1XBCnRFDI/t1Ddc/Jsnlfy4YzRN8otb/Xn6Yz9ACFvZIPGx/q0cqcrgVaR9rSQiSzsGTgUGHNJk8r3A4w9PSSB552Z9s6p5TsWK5ezlfgg+2ANKn1eJ6R/hzajS/B1bTAqYcl9ddo7prneoeAN5LjlMhc2e0cSVgQt8ALP+4x/bTMnDkMjG6R8lnDAxE27B2ZPaLOIOjkUMK+9mZa4RNBoCDG6J/fwPD1NUoVRCbyr/TVaS4EzyhfNK1QW3BlZ0NLSI/SFD3eryKaFQdacJHS31neQIDAQAB-----END PUBLIC KEY-----
|
||||
8
pom.xml
8
pom.xml
|
|
@ -29,6 +29,7 @@
|
|||
<module>mystyle-cloud-api</module>
|
||||
<module>mystyle-cloud-canal</module>
|
||||
<module>mystyle-cloud-mq</module>
|
||||
<module>mystyle-cloud-oauth</module>
|
||||
|
||||
</modules>
|
||||
|
||||
|
|
@ -53,6 +54,7 @@
|
|||
<opencv-platform.version>4.1.2-1.5.2</opencv-platform.version>
|
||||
<ffmpeg-platform.version>4.2.1-1.5.2</ffmpeg-platform.version>
|
||||
<fastjson.version>1.2.75</fastjson.version>
|
||||
<jwt.version>0.9.1</jwt.version>
|
||||
</properties>
|
||||
|
||||
<dependencyManagement>
|
||||
|
|
@ -198,7 +200,11 @@
|
|||
<artifactId>fastjson</artifactId>
|
||||
<version>${fastjson.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.jsonwebtoken</groupId>
|
||||
<artifactId>jjwt</artifactId>
|
||||
<version>${jwt.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
</project>
|
||||
Loading…
Reference in New Issue