一:配置文件

auth:
  tokenValiditySeconds: 1200  #token存储到redis的过期时间
  clientId: XcWebApp
  clientSecret: XcWebApp
  cookieDomain: xuecheng.com 
  cookieMaxAge: -1

二:配置类

日后再写!

三:业务代码

一:代码

@Service
public class AuthService {

    @Autowired
    private RestTemplate restTemplate;
    @Autowired
    private LoadBalancerClient loadBalancerClient;
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Value("${auth.tokenValiditySeconds}")
    private long ttl;

    /**
     * 用户认证获取令牌并存储到redis
     * @author : yechaoze
     * @date : 2019/7/25 12:28
     * @param username :
     * @param password :
     * @param clientId :
     * @param clientSecret :
     * @return : com.xuecheng.framework.domain.ucenter.ext.AuthToken
     */
    public AuthToken login(String username, String password, String clientId, String clientSecret) {
        //请求SpringSecurity获取了令牌
        AuthToken authToken = this.getAuthToken(username, password, clientId, clientSecret);
        if (authToken==null){
            ExceptionCast.cast(AuthCode.AUTH_LOGIN_APPLYTOKEN_FAIL);
        }
        //将token存储到redis
        //令牌
        String access_token = authToken.getAccess_token();
        //内容
        String content = JSON.toJSONString(authToken);
        boolean token = this.saveToken(access_token, content, ttl);
        if (!token){
            ExceptionCast.cast(AuthCode.AUTH_LOGIN_TOKEN_SAVEFAIL);
        }
        return authToken;
    }

    /**
     * 将token存储到redis
     * @author : yechaoze
     * @date : 2019/7/25 13:21
     * @param access_token :令牌
     * @param content : AuthToken对象的内容
     * @param ttl :过期时间
     * @return : boolean
     */
    private boolean saveToken(String access_token,String content,long ttl){
        String key="user_token:"+access_token;
        redisTemplate.boundValueOps(key).set(content,ttl,TimeUnit.SECONDS);
        Long expire = redisTemplate.getExpire(key,TimeUnit.SECONDS);
        return expire>0;
    }

    /**
     * 获取令牌
     * @author : yechaoze
     * @date : 2019/7/25 13:06
     * @param username :
     * @param password :
     * @param clientId :
     * @param clientSecret :
     * @return : java.util.Map
     */
    private AuthToken getAuthToken(String username, String password, String clientId, String clientSecret){
        //远程调用获取uri地址
        ServiceInstance serviceInstance = loadBalancerClient.choose(XcServiceList.XC_SERVICE_UCENTER_AUTH);
        URI uri = serviceInstance.getUri();
        String authUrl=uri+"/auth/oauth/token";

        //设置headers
        LinkedMultiValueMap<String,String> headers=new LinkedMultiValueMap<>();
        String httpBasic = this.getHttpBasic(clientId, clientSecret);
        headers.add("Authorization", httpBasic);

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

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

        //指定 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);
                }
            }
        });
        ResponseEntity<Map> exchange = restTemplate.exchange(authUrl, HttpMethod.POST, httpEntity, Map.class);
        Map jwtBody = exchange.getBody();
        if (jwtBody == null|| jwtBody.get("access_token")==null|| jwtBody.get("refresh_token")==null|| jwtBody.get("jti")==null){
            return null;
        }
        AuthToken authToken=new AuthToken();
        authToken.setAccess_token((String) jwtBody.get("jti"));//用户身份令牌
        authToken.setJwt_token((String) jwtBody.get("access_token"));//jwt令牌
        authToken.setRefresh_token((String) jwtBody.get("refresh_token"));//刷新令牌
        return authToken;
    }

    /**
     * 获取httpBasic
     * @author : yechaoze
     * @date : 2019/7/25 12:31
     * @param clientId :
     * @param clientSecret :
     * @return : java.lang.String 返回格式 Basic xxxxxxxxxxxxxxxxxx
     */
    private String getHttpBasic(String clientId, String clientSecret){
        String string=clientId+":"+clientSecret;
        byte[] bytes = Base64Utils.encode(string.getBytes());
        return "Basic "+new String(bytes);
    }
}

二:代码解释

  • getHttpBasic

使用配置文件中的clientId,clientSecret获取返回格式为Basic xxxxxxxxxx的数据

  • getAuthToken

先远程调用获取uri,拼接url,设置headers和body,使用restTemplate.exchang

说明:1)url: 请求地址;

2)method: 请求类型(如:POST,PUT,DELETE,GET);

3)requestEntity: 请求实体,封装请求头,请求内容

4)responseType: 响应类型,根据服务接口的返回类型决定

5)uriVariables: url中参数变量值

  • saveToken

access_token:令牌

content:AuthToken对象的内容

ttl:超时时间

  • login

调用getAuthToken方法及saveToken方法

四:Controller的实现

一:代码

import javax.servlet.http.HttpServletResponse;

@RestController
@RequestMapping("/")
public class AuthController implements AuthControllerApi {

    @Autowired
    private AuthService authService;
    @Value("${auth.clientId}")
    private String clientId;
    @Value("${auth.clientSecret}")
    private String clientSecret;
    @Value("${auth.cookieDomain}")
    private String domain;
    @Value("${auth.cookieMaxAge}")
    private int cookieMaxAge;

    @Override
    @PostMapping("/userLogin")
    public LoginResult login(LoginRequest loginRequest) {
        if (loginRequest==null|| StringUtils.isEmpty(loginRequest.getUsername())){
            ExceptionCast.cast(AuthCode.AUTH_USERNAME_NONE);
        }
        if (loginRequest==null|| StringUtils.isEmpty(loginRequest.getPassword())){
            ExceptionCast.cast(AuthCode.AUTH_PASSWORD_NONE);
        }
        String username = loginRequest.getUsername();
        String password = loginRequest.getPassword();
        AuthToken authToken= authService.login(username,password,clientId,clientSecret);
        //将令牌存储到cookie
        String access_token = authToken.getAccess_token();
        this.saveCookie(access_token);
        return new LoginResult(CommonCode.SUCCESS,access_token);
    }

    /**
     * 存储cookie
     * @author : yechaoze
     * @date : 2019/7/25 13:51
     * @param token :
     * @return : void
     */
    private void saveCookie(String token){
        //HttpServletResponse response,String domain,String path,String name,String value,int maxAge,boolean httpOnly
        HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
        CookieUtil.addCookie(response,domain,"/","uid",token,cookieMaxAge,false);
    }

    @Override
    public ResponseResult logout() {
        return null;
    }
}

二:代码解释

  • saveCookie

使用cookieUtils把cookie存入在xuecheng.com域名中

  • login

调用service中的login方法,并调用saveCookie实现将cookie存入xuecheng.com 将access_token,refresh_token,jti存入redis

三:结果

测试成功
cookie测试成功
redis测试成功

五:总结

写的有点乱,过几天重新整理一下


For sharing , For emulating , For enterprising