单点登录

一,单点登录概述

(一)什么是单点登录:每个子系统从第三方认证系统中查找而不是每个系统都通过各自的session校验。

(二)单点登录的特点是:
1、认证系统为独立的系统。
2、各子系统通过Http或其它协议与认证系统通信,完成用户认证。
3、用户身份信息存储在Redis集群。

(三)单点登录实现框架:

apache Shiro

CAS

springsecurity

二。Oauth2认证微信认证第三方登录

1.授权码模式:资源拥有者(用户)发起微信登录,平台调用微信接口,到达授权页面,手机wx扫码登录用户同意授权,微信会对用户进行验证,通过后给平台一个授权码,平台

携带授权码到微信认证服务申请令牌,并返回令牌到平台,平台再携带令牌调微信用户信息服务,微信用户信息服务校验令牌合法性,响应给平台,

平台显示微信头像。

客户端(平台)拿到授权码去认证服务申请令牌,授权服务通过私钥加密生成令牌,

令牌给客户端,携带令牌访问资源服务

课程服务相当于资源存储公钥(根据公钥校验令牌合法性===公钥把令牌解开,放行;;解不开拒绝服务)

课程服务相当于资源服务

对swagger进行放行

 "/swagger-resources","/swagger-resources/configuration/security",
                        "/swagger-ui.html","/webjars/**","/course/coursepic/list/*").permitAll()
mport org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.stream.Collectors;

@Configuration
@EnableResourceServer
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)//激活方法上的PreAuthorize注解
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {

    //公钥
    private static final String PUBLIC_KEY = "publickey.txt";

    //定义JwtTokenStore,使用jwt令牌
    @Bean
    public TokenStore tokenStore(JwtAccessTokenConverter jwtAccessTokenConverter) {
        return new JwtTokenStore(jwtAccessTokenConverter);
    }

    //定义JJwtAccessTokenConverter,使用jwt令牌
    @Bean
    public JwtAccessTokenConverter jwtAccessTokenConverter() {
        JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
        converter.setVerifierKey(getPubKey());
        return converter;
    }
    /**
     * 获取非对称加密公钥 Key
     * @return 公钥 Key
     */
    private String getPubKey() {
        Resource resource = new ClassPathResource(PUBLIC_KEY);
        try {
            InputStreamReader inputStreamReader = new InputStreamReader(resource.getInputStream());
            BufferedReader br = new BufferedReader(inputStreamReader);
            return br.lines().collect(Collectors.joining("
"));
        } catch (IOException ioe) {
            return null;
        }
    }
    //Http安全配置,对每个到达系统的http请求链接进行校验
    @Override
    public void configure(HttpSecurity http) throws Exception {
        //所有请求必须认证通过
        http.authorizeRequests()
                .antMatchers("/v2/api-docs", "/swagger-resources/configuration/ui",
                        "/swagger-resources","/swagger-resources/configuration/security",
                        "/swagger-ui.html","/webjars/**","/course/coursepic/list/*").permitAll()
                .anyRequest().authenticated();
    }
}

访问课程服务只有:头部KEY:authorization

value:Bear+accesstoken

才可以访问

2.密码算法模式

不用申请授权码,用户名,密码就可以;

jwt中包含了用户信息,可以避免资源服务解决不了验证还要请求认证服务来验证。效率高

是个json串便于解析,易拓展,非对称安全,但长

分为头部(加密算法),负载(自己加),签名(认证服务端签发的唯一防止窃取)。

(一)认证服务的controller

如何申请令牌

clientid,clientpassword

bodyheader封装在HTTPentity

getHttpBasic
        MultiValueMap<String, String> body = new LinkedMultiValueMap<>();
        body.add("grant_type","password");
        body.add("username","itcast");
        body.add("password","123");


        MultiValueMap<String, String> headers = new LinkedMultiValueMap<>();
        headers.add("Authorization",this.getHttpBasic("XcWebApp","XcWebApp"));

        HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity<>(body,headers);



private String getHttpBasic(String clientId, String clientPassword) {

String value =clientId+":"+clientPassword ;
byte[] encode = Base64Utils.encode(value.getBytes());
return "Basic "+new String(encode);
}

uri

        //http://localhost:40400/auth/oauth/token
        ServiceInstance serviceInstance = loadBalancerClient.choose(XcServiceList.XC_SERVICE_UCENTER_AUTH);
        // http://localhost:40400
        URI uri = serviceInstance.getUri();
        String url = uri+"/auth/oauth/token";
ResponseEntity<Map> responseEntity = restTemplate.exchange(url, HttpMethod.POST, requestEntity, Map.class);

Map map = responseEntity.getBody();

 1 Override
 2     @PostMapping("/userlogin")
 3     public LoginResult login(LoginRequest loginRequest) {
 4 
 5         //判断参数
 6         if (StringUtils.isEmpty(loginRequest.getUsername())){
 7             ExceptionCast.cast(AuthCode.AUTH_USERNAME_NONE);
 8         }
 9         if (StringUtils.isEmpty(loginRequest.getPassword())){
10             ExceptionCast.cast(AuthCode.AUTH_PASSWORD_NONE);
11         }
12 
13         //申请令牌
14         AuthToken authToken = authService.login(loginRequest.getUsername(),loginRequest.getPassword(),clientId,clientSecret);
15 
16         String jti = authToken.getJti();
17 
18         //将令牌信息存入cookie
19         this.saveTokenToCookie(jti);
20 
21         return new LoginResult(CommonCode.SUCCESS,jti);
22     }
23 
24     private void saveTokenToCookie(String jti) {
25         HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
26 
27         //httpOnly:false。 允许浏览器获取cookie
28         CookieUtil.addCookie(response,cookieDomain,"/","uid",jti,cookieMaxAge,false);
29     }
测试


实际结果


(二)认证服务的service

  public AuthToken login(String username, String password, String clientId, String clientSecret) {

        //申请令牌
        AuthToken authToken = this.applyToken(username,password,clientId,clientSecret);

        //将令牌存入redis
        boolean result =  this.saveTokenToRedis(authToken);
        if (!result){
            //存入失败
            ExceptionCast.cast(AuthCode.AUTH_LOGIN_TOKEN_SAVEFAIL);
        }
        return authToken;
    }

    //存入redis
    private boolean saveTokenToRedis(AuthToken authToken) {
        String key = "user_token:"+authToken.getJti();
        String tokenString = JSON.toJSONString(authToken);
        stringRedisTemplate.boundValueOps(key).set(tokenString,tokenValiditySeconds, TimeUnit.SECONDS);

        Long expire = stringRedisTemplate.getExpire(key);
        return expire>0;

    }

    //申请令牌
    private AuthToken applyToken(String username, String password, String clientId, String clientSecret) {
        ServiceInstance serviceInstance = loadBalancerClient.choose(XcServiceList.XC_SERVICE_UCENTER_AUTH);

        URI uri = serviceInstance.getUri();
        String url = uri+"/auth/oauth/token";

        MultiValueMap<String, String> body = new LinkedMultiValueMap<>();
        body.add("grant_type","password");
        body.add("username",username);
        body.add("password",password);

        MultiValueMap<String, String> headers = new LinkedMultiValueMap<>();
        headers.add("Authorization",this.getHttpBasic(clientId,clientSecret));

        HttpEntity<MultiValueMap<String,String>> requestEntity = new HttpEntity<>(body,headers);

        restTemplate.setErrorHandler(new DefaultResponseErrorHandler(){
            @Override
            public void handleError(ClientHttpResponse response) throws IOException {
                if (response.getRawStatusCode() != 400 && response.getRawStatusCode() != 401){
                    super.handleError(response);
                }
            }
        });

        ResponseEntity<Map> responseEntity = restTemplate.exchange(url, HttpMethod.POST, requestEntity, Map.class);

        Map map = responseEntity.getBody();

        if (map == null || map.get("access_token")==null || map.get("refresh_token")==null || map.get("jti")==null){
            ExceptionCast.cast(AuthCode.AUTH_LOGIN_APPLYTOKEN_FAIL);
        }

        AuthToken authToken = new AuthToken();
        authToken.setAccess_token((String) map.get("access_token"));
        authToken.setRefresh_token((String) map.get("refresh_token"));
        authToken.setJti((String) map.get("jti"));

        return authToken;
    }

三,具体单点登录实现认证服务

(一)配置文件

1

AuthorizationServerConfig 
密钥非对称加密,私钥加密,公钥解密
package com.xuecheng.auth.config;

import org.springframework.beans.factory.annotation.Autowired;
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;


@Configuration
@EnableAuthorizationServer
class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
    @Autowired
    private DataSource dataSource;
    //jwt令牌转换器
    @Autowired
    private JwtAccessTokenConverter jwtAccessTokenConverter;
    @Autowired
    UserDetailsService userDetailsService;
    @Autowired
    AuthenticationManager authenticationManager;
    @Autowired
    TokenStore tokenStore;
    @Autowired
    private CustomUserAuthenticationConverter customUserAuthenticationConverter;

    //读取密钥的配置
    @Bean("keyProp")
    public KeyProperties keyProperties(){
        return new KeyProperties();
    }

    @Resource(name = "keyProp")
    private KeyProperties keyProperties;


    //客户端配置
    @Bean
    public ClientDetailsService clientDetails() {
        return new JdbcClientDetailsService(dataSource);
    }
    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.jdbc(this.dataSource).clients(this.clientDetails());
       /* clients.inMemory()
                .withClient("XcWebApp")//客户端id
                .secret("XcWebApp")//密码,要保密
                .accessTokenValiditySeconds(60)//访问令牌有效期
                .refreshTokenValiditySeconds(60)//刷新令牌有效期
                //授权客户端请求认证服务的类型authorization_code:根据授权码生成令牌,
                // client_credentials:客户端认证,refresh_token:刷新令牌,password:密码方式认证
                .authorizedGrantTypes("authorization_code", "client_credentials", "refresh_token", "password")
                .scopes("app");//客户端范围,名称自定义,必填*/
    }

    //token的存储方法
//    @Bean
//    public InMemoryTokenStore tokenStore() {
//        //将令牌存储到内存
//        return new InMemoryTokenStore();
//    }
//    @Bean
//    public TokenStore tokenStore(RedisConnectionFactory redisConnectionFactory){
//        RedisTokenStore redisTokenStore = new RedisTokenStore(redisConnectionFactory);
//        return redisTokenStore;
//    }
    @Bean
    @Autowired
    public TokenStore tokenStore(JwtAccessTokenConverter jwtAccessTokenConverter) {
        return new JwtTokenStore(jwtAccessTokenConverter);
    }
    @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;
    }
    //授权服务器端点配置
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        /*Collection<TokenEnhancer> tokenEnhancers = applicationContext.getBeansOfType(TokenEnhancer.class).values();
        TokenEnhancerChain tokenEnhancerChain=new TokenEnhancerChain();
        tokenEnhancerChain.setTokenEnhancers(new ArrayList<>(tokenEnhancers));

        DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
        defaultTokenServices.setReuseRefreshToken(true);
        defaultTokenServices.setSupportRefreshToken(true);
        defaultTokenServices.setTokenStore(tokenStore);
        defaultTokenServices.setAccessTokenValiditySeconds(1111111);
        defaultTokenServices.setRefreshTokenValiditySeconds(1111111);
        defaultTokenServices.setTokenEnhancer(tokenEnhancerChain);

        endpoints
                .authenticationManager(authenticationManager)
                .userDetailsService(userDetailsService)
                        //.tokenStore(tokenStore);
                .tokenServices(defaultTokenServices);*/
        endpoints.accessTokenConverter(jwtAccessTokenConverter)
                .authenticationManager(authenticationManager)//认证管理器
                .tokenStore(tokenStore)//令牌存储
                .userDetailsService(userDetailsService);//用户信息service
    }

    //授权服务器的安全配置
    @Override
    public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
//        oauthServer.checkTokenAccess("isAuthenticated()");//校验token需要认证通过,可采用http basic认证
        oauthServer.allowFormAuthenticationForClients()
                .passwordEncoder(new BCryptPasswordEncoder())
                .tokenKeyAccess("permitAll()")
                .checkTokenAccess("isAuthenticated()");
    }



}



2
CustomUserAuthenticationConverter
生成令牌信息
package com.xuecheng.auth.config;

import com.xuecheng.auth.service.UserJwt;
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.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.LinkedHashMap;
import java.util.Map;

@Component
public class CustomUserAuthenticationConverter extends DefaultUserAuthenticationConverter {
    @Autowired
    UserDetailsService userDetailsService;

    @Override
    public Map<String, ?> convertUserAuthentication(Authentication authentication) {
        LinkedHashMap response = new LinkedHashMap();
        String name = authentication.getName();
        response.put("user_name", 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());
        response.put("utype",userJwt.getUtype());
        response.put("userpic",userJwt.getUserpic());
        response.put("companyId",userJwt.getCompanyId());
        if (authentication.getAuthorities() != null && !authentication.getAuthorities().isEmpty()) {
            response.put("authorities", AuthorityUtils.authorityListToSet(authentication.getAuthorities()));
        }

        return response;
    }


}


3
WebSecurityConfig
对登录放行
密码加盐加密

 1 import org.springframework.context.annotation.Bean;
 2 import org.springframework.context.annotation.Configuration;
 3 import org.springframework.core.annotation.Order;
 4 import org.springframework.security.authentication.AuthenticationManager;
 5 import org.springframework.security.config.annotation.web.builders.HttpSecurity;
 6 import org.springframework.security.config.annotation.web.builders.WebSecurity;
 7 import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
 8 import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
 9 import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
10 import org.springframework.security.crypto.password.PasswordEncoder;
11 
12 @Configuration
13 @EnableWebSecurity
14 @Order(-1)
15 class WebSecurityConfig extends WebSecurityConfigurerAdapter {
16 
17     @Override
18     public void configure(WebSecurity web) throws Exception {
19         web.ignoring().antMatchers("/userlogin","/userlogout","/userjwt");
20 
21     }
22     @Bean
23     @Override
24     public AuthenticationManager authenticationManagerBean() throws Exception {
25         AuthenticationManager manager = super.authenticationManagerBean();
26         return manager;
27     }
28     //采用bcrypt对密码进行编码
29     @Bean
30     public PasswordEncoder passwordEncoder() {
31         return new BCryptPasswordEncoder();
32     }
33 
34     @Override
35     public void configure(HttpSecurity http) throws Exception {
36         http.csrf().disable()
37                 .httpBasic().and()
38                 .formLogin()
39                 .and()
40                 .authorizeRequests().anyRequest().authenticated();
41 
42     }
43 }

authservice写认证

package com.xuecheng.auth.service;


import com.alibaba.fastjson.JSON;
import com.xuecheng.filesystem.framework.client.XcServiceList;
import com.xuecheng.filesystem.framework.domain.ucenter.ext.AuthToken;
import com.xuecheng.filesystem.framework.domain.ucenter.response.AuthCode;
import com.xuecheng.filesystem.framework.exception.ExceptionCast;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.data.redis.core.StringRedisTemplate;
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.RestTemplate;

import java.io.IOException;
import java.net.URI;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Service
public class AuthService {

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private LoadBalancerClient loadBalancerClient;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Value("${auth.tokenValiditySeconds}")
    private long tokenValiditySeconds;

    /**
     * 用户认证登录,申请令牌
     * @param username
     * @param password
     * @param clientId
     * @param clientSecret
     * @return
     */
    public AuthToken login(String username, String password, String clientId, String clientSecret) {

        //申请令牌
        AuthToken authToken = this.applyToken(username,password,clientId,clientSecret);

        //将令牌存入redis
        boolean result =  this.saveTokenToRedis(authToken);
        if (!result){
            //存入失败
            ExceptionCast.cast(AuthCode.AUTH_LOGIN_TOKEN_SAVEFAIL);
        }
        return authToken;
    }

    //存入redis
    private boolean saveTokenToRedis(AuthToken authToken) {
        String key = "user_token:"+authToken.getJti();
        String tokenString = JSON.toJSONString(authToken);
        stringRedisTemplate.boundValueOps(key).set(tokenString,tokenValiditySeconds, TimeUnit.SECONDS);

        Long expire = stringRedisTemplate.getExpire(key);
        return expire>0;

    }

    //申请令牌
    private AuthToken applyToken(String username, String password, String clientId, String clientSecret) {
        ServiceInstance serviceInstance = loadBalancerClient.choose(XcServiceList.XC_SERVICE_UCENTER_AUTH);

        URI uri = serviceInstance.getUri();
        String url = uri+"/auth/oauth/token";

        MultiValueMap<String, String> body = new LinkedMultiValueMap<>();
        body.add("grant_type","password");
        body.add("username",username);
        body.add("password",password);

        MultiValueMap<String, String> headers = new LinkedMultiValueMap<>();
        headers.add("Authorization",this.getHttpBasic(clientId,clientSecret));

        HttpEntity<MultiValueMap<String,String>> requestEntity = new HttpEntity<>(body,headers);

        restTemplate.setErrorHandler(new DefaultResponseErrorHandler(){
            @Override
            public void handleError(ClientHttpResponse response) throws IOException {
                if (response.getRawStatusCode() != 400 && response.getRawStatusCode() != 401){
                    super.handleError(response);
                }
            }
        });

        ResponseEntity<Map> responseEntity = restTemplate.exchange(url, HttpMethod.POST, requestEntity, Map.class);

        Map map = responseEntity.getBody();

        if (map == null || map.get("access_token")==null || map.get("refresh_token")==null || map.get("jti")==null){
            ExceptionCast.cast(AuthCode.AUTH_LOGIN_APPLYTOKEN_FAIL);
        }

        AuthToken authToken = new AuthToken();
        authToken.setAccess_token((String) map.get("access_token"));
        authToken.setRefresh_token((String) map.get("refresh_token"));
        authToken.setJti((String) map.get("jti"));

        return authToken;
    }

    private String getHttpBasic(String clientId, String clientSecret) {
        String value = clientId+":"+clientSecret;
        byte[] encode = Base64Utils.encode(value.getBytes());
        return "Basic "+new String(encode);
    }


    public AuthToken getTokenFormRedis(String jti) {
        String key="user_token:"+jti;
        String tokenString = stringRedisTemplate.boundValueOps(key).get();
        AuthToken authToken = JSON.parseObject(tokenString, AuthToken.class);

        return authToken;
    }

    public void delTokenFromRedis(String jti) {
    String key="user_token:"+jti;
    stringRedisTemplate.delete(key);
    }
}

userjwt用户信息融到令牌中

import lombok.Data;
import lombok.ToString;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.User;

import java.util.Collection;

@Data
@ToString
public class UserJwt extends User {

    private String id;
    private String name;
    private String userpic;
    private String utype;
    private String companyId;

    public UserJwt(String username, String password, Collection<? extends GrantedAuthority> authorities) {
        super(username, password, authorities);
    }

}

yml配置

1访问路径,redis信息

2auth设置redis过期时间==session过期时间(过期重新登录用)

3私钥位置

4cookie域名(适配到不同域中)和maxage

server:
  port: ${PORT:40400}
  servlet:
    context-path: /auth
spring:
  application:
    name: xc-service-ucenter-auth
  redis:
    host: ${REDIS_HOST:127.0.0.1}
    port: ${REDIS_PORT:6379}
    timeout: 5000 #连接超时 毫秒
    jedis:
      pool:
        maxActive: 3
        maxIdle: 3
        minIdle: 1
        maxWait: -1 #连接池最大等行时间 -1没有限制
  datasource:
    druid:
      url: ${MYSQL_URL:jdbc:mysql://localhost:3306/xc_user?characterEncoding=utf-8}
      username: root
      password: root
      driverClassName: com.mysql.jdbc.Driver
      initialSize: 5  #初始建立连接数量
      minIdle: 5  #最小连接数量
      maxActive: 20 #最大连接数量
      maxWait: 10000  #获取连接最大等待时间,毫秒
      testOnBorrow: true #申请连接时检测连接是否有效
      testOnReturn: false #归还连接时检测连接是否有效
      timeBetweenEvictionRunsMillis: 60000 #配置间隔检测连接是否有效的时间(单位是毫秒)
      minEvictableIdleTimeMillis: 300000  #连接在连接池的最小生存时间(毫秒)
auth:
  tokenValiditySeconds: 1200  #token存储到redis的过期时间
  clientId: XcWebApp
  clientSecret: XcWebApp
  cookieDomain: xuecheng.com
  cookieMaxAge: -1
encrypt:
  key-store:
    location: classpath:/xc.keystore
    secret: xuechengkeystore
    alias: xckey
    password: xuecheng
eureka:
  client:
    registerWithEureka: true #服务注册开关
    fetchRegistry: true #服务发现开关
    serviceUrl: #Eureka客户端与Eureka服务端进行交互的地址,多个中间用逗号分隔
      defaultZone: ${EUREKA_SERVER:http://localhost:50101/eureka/,http://localhost:50102/eureka/}
  instance:
    prefer-ip-address:  true  #将自己的ip地址注册到Eureka服务中
    ip-address: ${IP_ADDRESS:127.0.0.1}
    instance-id: ${spring.application.name}:${server.port} #指定实例id
ribbon:
  MaxAutoRetries: 2 #最大重试次数,当Eureka中可以找到服务,但是服务连不上时将会重试,如果eureka中找不到服务则直接走断路器
  MaxAutoRetriesNextServer: 3 #切换实例的重试次数
  OkToRetryOnAllOperations: false  #对所有操作请求都进行重试,如果是get则可以,如果是post,put等操作没有实现幂等的情况下是很危险的,所以设置为false
  ConnectTimeout: 5000  #请求连接的超时时间
  ReadTimeout: 6000 #请求处理的超时时间

当一个男人不再对你啰嗦,不再缠着你,不再没事找你,对你说话也客气了,也不再气你了。那么恭喜你,你已经成功的失去了他。别嫌弃男人幼稚,那是他喜欢你,爱你。女人说男人像小孩子一样不成熟,可又有谁知道,男人在自己喜欢的女人面前才像小孩子,如果不喜欢你了,不爱你了,他比你爸还成熟。
原文地址:https://www.cnblogs.com/fengtangjiang/p/11147245.html