diff --git a/mystyle-cloud-api/src/main/java/com/zhangmeng/api/service/oauth/AuthControllerApi.java b/mystyle-cloud-api/src/main/java/com/zhangmeng/api/service/oauth/AuthControllerApi.java
new file mode 100644
index 0000000..e9e9b04
--- /dev/null
+++ b/mystyle-cloud-api/src/main/java/com/zhangmeng/api/service/oauth/AuthControllerApi.java
@@ -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);
+}
diff --git a/mystyle-cloud-model/pom.xml b/mystyle-cloud-model/pom.xml
index 35836c9..ac1b1f8 100644
--- a/mystyle-cloud-model/pom.xml
+++ b/mystyle-cloud-model/pom.xml
@@ -89,5 +89,15 @@
com.alibaba
fastjson
+
+
+ io.jsonwebtoken
+ jjwt
+
+
+
+ org.springframework.boot
+ spring-boot-starter-security
+
\ No newline at end of file
diff --git a/mystyle-cloud-model/src/main/java/com/zhangmeng/model/entity/OauthConfig.java b/mystyle-cloud-model/src/main/java/com/zhangmeng/model/entity/OauthConfig.java
new file mode 100644
index 0000000..16587b9
--- /dev/null
+++ b/mystyle-cloud-model/src/main/java/com/zhangmeng/model/entity/OauthConfig.java
@@ -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 {
+
+ private Integer ttl;
+
+ private String clientId;
+
+ private String clientSecret;
+
+ private String cookieDomain;
+
+ private Integer cookieMaxAge;
+}
diff --git a/mystyle-cloud-oauth/pom.xml b/mystyle-cloud-oauth/pom.xml
new file mode 100644
index 0000000..1f2075f
--- /dev/null
+++ b/mystyle-cloud-oauth/pom.xml
@@ -0,0 +1,68 @@
+
+
+
+ mystyle-cloud-parent
+ com.zhangmeng
+ 1.0-SNAPSHOT
+
+ 4.0.0
+
+ mystyle-cloud-oauth
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+
+ org.springframework.boot
+ spring-boot-starter-amqp
+
+
+
+ com.alibaba.cloud
+ spring-cloud-starter-alibaba-nacos-discovery
+
+
+
+ org.springframework.cloud
+ spring-cloud-starter-sleuth
+
+
+
+ org.springframework.cloud
+ spring-cloud-sleuth-zipkin
+
+
+
+ org.springframework.security
+ spring-security-data
+
+
+
+ org.springframework.cloud
+ spring-cloud-starter-oauth2
+ 2.2.4.RELEASE
+
+
+
+ org.springframework.cloud
+ spring-cloud-starter-openfeign
+
+
+
+ org.springframework.cloud
+ spring-cloud-starter-loadbalancer
+
+
+
+ com.zhangmeng
+ mystyle-cloud-api
+ 1.0-SNAPSHOT
+
+
+
+
\ No newline at end of file
diff --git a/mystyle-cloud-oauth/src/main/java/com/zhangmeng/oauth/OauthApplication.java b/mystyle-cloud-oauth/src/main/java/com/zhangmeng/oauth/OauthApplication.java
new file mode 100644
index 0000000..e7c3554
--- /dev/null
+++ b/mystyle-cloud-oauth/src/main/java/com/zhangmeng/oauth/OauthApplication.java
@@ -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);
+ }
+}
diff --git a/mystyle-cloud-oauth/src/main/java/com/zhangmeng/oauth/config/AuthorizationServerConfig.java b/mystyle-cloud-oauth/src/main/java/com/zhangmeng/oauth/config/AuthorizationServerConfig.java
new file mode 100644
index 0000000..039057f
--- /dev/null
+++ b/mystyle-cloud-oauth/src/main/java/com/zhangmeng/oauth/config/AuthorizationServerConfig.java
@@ -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;
+ }
+}
diff --git a/mystyle-cloud-oauth/src/main/java/com/zhangmeng/oauth/config/CustomUserAuthenticationConverter.java b/mystyle-cloud-oauth/src/main/java/com/zhangmeng/oauth/config/CustomUserAuthenticationConverter.java
new file mode 100644
index 0000000..626fa77
--- /dev/null
+++ b/mystyle-cloud-oauth/src/main/java/com/zhangmeng/oauth/config/CustomUserAuthenticationConverter.java
@@ -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 convertUserAuthentication(Authentication authentication) {
+ HashMap 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;
+ }
+}
diff --git a/mystyle-cloud-oauth/src/main/java/com/zhangmeng/oauth/config/FeignOauth2RequestInterceptor.java b/mystyle-cloud-oauth/src/main/java/com/zhangmeng/oauth/config/FeignOauth2RequestInterceptor.java
new file mode 100644
index 0000000..df63033
--- /dev/null
+++ b/mystyle-cloud-oauth/src/main/java/com/zhangmeng/oauth/config/FeignOauth2RequestInterceptor.java
@@ -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 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);
+ }
+}
diff --git a/mystyle-cloud-oauth/src/main/java/com/zhangmeng/oauth/config/UserDetailsServiceImpl.java b/mystyle-cloud-oauth/src/main/java/com/zhangmeng/oauth/config/UserDetailsServiceImpl.java
new file mode 100644
index 0000000..16116e8
--- /dev/null
+++ b/mystyle-cloud-oauth/src/main/java/com/zhangmeng/oauth/config/UserDetailsServiceImpl.java
@@ -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 permissions = this.adminFeign.findByUserId(user.getId());
+ Set 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);
+ }
+}
diff --git a/mystyle-cloud-oauth/src/main/java/com/zhangmeng/oauth/config/WebSecurityConfig.java b/mystyle-cloud-oauth/src/main/java/com/zhangmeng/oauth/config/WebSecurityConfig.java
new file mode 100644
index 0000000..9f3cbf9
--- /dev/null
+++ b/mystyle-cloud-oauth/src/main/java/com/zhangmeng/oauth/config/WebSecurityConfig.java
@@ -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(); //其他请求都需要经过验证
+ }
+}
diff --git a/mystyle-cloud-oauth/src/main/java/com/zhangmeng/oauth/controller/AuthController.java b/mystyle-cloud-oauth/src/main/java/com/zhangmeng/oauth/controller/AuthController.java
new file mode 100644
index 0000000..b03c97e
--- /dev/null
+++ b/mystyle-cloud-oauth/src/main/java/com/zhangmeng/oauth/controller/AuthController.java
@@ -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 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);
+ }
+}
diff --git a/mystyle-cloud-oauth/src/main/java/com/zhangmeng/oauth/dao/OauthConfigDao.java b/mystyle-cloud-oauth/src/main/java/com/zhangmeng/oauth/dao/OauthConfigDao.java
new file mode 100644
index 0000000..b012673
--- /dev/null
+++ b/mystyle-cloud-oauth/src/main/java/com/zhangmeng/oauth/dao/OauthConfigDao.java
@@ -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 {
+}
diff --git a/mystyle-cloud-oauth/src/main/java/com/zhangmeng/oauth/dto/AuthToken.java b/mystyle-cloud-oauth/src/main/java/com/zhangmeng/oauth/dto/AuthToken.java
new file mode 100644
index 0000000..f003f65
--- /dev/null
+++ b/mystyle-cloud-oauth/src/main/java/com/zhangmeng/oauth/dto/AuthToken.java
@@ -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;
+}
diff --git a/mystyle-cloud-oauth/src/main/java/com/zhangmeng/oauth/dto/JwtToken.java b/mystyle-cloud-oauth/src/main/java/com/zhangmeng/oauth/dto/JwtToken.java
new file mode 100644
index 0000000..1dfa0d4
--- /dev/null
+++ b/mystyle-cloud-oauth/src/main/java/com/zhangmeng/oauth/dto/JwtToken.java
@@ -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 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();
+ }
+}
\ No newline at end of file
diff --git a/mystyle-cloud-oauth/src/main/java/com/zhangmeng/oauth/dto/UserJwt.java b/mystyle-cloud-oauth/src/main/java/com/zhangmeng/oauth/dto/UserJwt.java
new file mode 100644
index 0000000..7019c7f
--- /dev/null
+++ b/mystyle-cloud-oauth/src/main/java/com/zhangmeng/oauth/dto/UserJwt.java
@@ -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;
+ }
+}
\ No newline at end of file
diff --git a/mystyle-cloud-oauth/src/main/java/com/zhangmeng/oauth/feign/AdminFeign.java b/mystyle-cloud-oauth/src/main/java/com/zhangmeng/oauth/feign/AdminFeign.java
new file mode 100644
index 0000000..1db15ea
--- /dev/null
+++ b/mystyle-cloud-oauth/src/main/java/com/zhangmeng/oauth/feign/AdminFeign.java
@@ -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);
+}
diff --git a/mystyle-cloud-oauth/src/main/java/com/zhangmeng/oauth/service/AuthService.java b/mystyle-cloud-oauth/src/main/java/com/zhangmeng/oauth/service/AuthService.java
new file mode 100644
index 0000000..37da596
--- /dev/null
+++ b/mystyle-cloud-oauth/src/main/java/com/zhangmeng/oauth/service/AuthService.java
@@ -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);
+}
diff --git a/mystyle-cloud-oauth/src/main/java/com/zhangmeng/oauth/service/OauthConfigService.java b/mystyle-cloud-oauth/src/main/java/com/zhangmeng/oauth/service/OauthConfigService.java
new file mode 100644
index 0000000..d53b41c
--- /dev/null
+++ b/mystyle-cloud-oauth/src/main/java/com/zhangmeng/oauth/service/OauthConfigService.java
@@ -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 {
+
+ public OauthConfig oauthConfig();
+}
\ No newline at end of file
diff --git a/mystyle-cloud-oauth/src/main/java/com/zhangmeng/oauth/service/impl/AuthServiceImpl.java b/mystyle-cloud-oauth/src/main/java/com/zhangmeng/oauth/service/impl/AuthServiceImpl.java
new file mode 100644
index 0000000..e0bf0b5
--- /dev/null
+++ b/mystyle-cloud-oauth/src/main/java/com/zhangmeng/oauth/service/impl/AuthServiceImpl.java
@@ -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 formData = new LinkedMultiValueMap<>();
+ //授权方式
+ formData.add("grant_type", "password");
+ //账号
+ formData.add("username", username);
+ //密码
+ formData.add("password", password);
+ //定义头
+ MultiValueMap 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