Przeglądaj źródła

认证服务验证码登陆,和密码登陆RSA加密流程

suxiaoyang 6 lat temu
rodzic
commit
6d3ac1653d

+ 2 - 0
common/common-entity/src/main/java/com/yihu/jw/entity/base/sms/SmsDO.java

@ -1,5 +1,6 @@
package com.yihu.jw.entity.base.sms;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.yihu.jw.entity.UuidIdentityEntity;
import javax.persistence.*;
@ -85,6 +86,7 @@ public class SmsDO extends UuidIdentityEntity {
	}
	@Column(name = "deadline", nullable = false)
	@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+08:00")
	public Date getDeadline() {
		return deadline;
	}

+ 3 - 1
common/common-rest-model/src/main/java/com/yihu/jw/restmodel/base/sms/SmsVO.java

@ -1,5 +1,6 @@
package com.yihu.jw.restmodel.base.sms;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.yihu.jw.entity.base.sms.SmsTemplateDO;
import com.yihu.jw.restmodel.UuidIdentityVO;
import io.swagger.annotations.ApiModel;
@ -31,7 +32,7 @@ public class SmsVO extends UuidIdentityVO {
    @ApiModelProperty(value = "短信内容", example = "【i健康综合管理平台】您使用的是i健康综合管理平台短信模板,您的验证码是826612,请于10分钟内正确输入!")
    private String content;
    //过期时间
    @ApiModelProperty(value = "应用ID", example = "EwC0iRSrcS")
    @ApiModelProperty(value = "过期时间", example = "2018-09-03 15:34:34")
    private Date deadline;
    //验证码
    private String captcha;
@ -78,6 +79,7 @@ public class SmsVO extends UuidIdentityVO {
        this.content = content;
    }
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+08:00")
    public Date getDeadline() {
        return deadline;
    }

+ 10 - 0
server/svr-authentication/src/main/java/com/yihu/AuthServer.java

@ -4,6 +4,9 @@ import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.support.SpringBootServletInitializer;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
/**
 * Created by progr1mmer on 2018/8/29.
@ -19,4 +22,11 @@ public class AuthServer extends SpringBootServletInitializer {
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(AuthServer.class);
    }
    @Bean
    @LoadBalanced
    RestTemplate restTemplate() {
        return new RestTemplate();
    }
}

+ 42 - 0
server/svr-authentication/src/main/java/com/yihu/jw/security/model/Captcha.java

@ -0,0 +1,42 @@
package com.yihu.jw.security.model;
import java.io.Serializable;
import java.util.Date;
/**
 * Model - 验证码
 * Created by progr1mmer on 2018/9/3.
 */
public class Captcha implements Serializable {
    //验证码
    private String code;
    //过期时间(秒)
    private int expiresIn;
    //请求间隔(秒)
    private int interval;
    public String getCode() {
        return code;
    }
    public void setCode(String code) {
        this.code = code;
    }
    public int getExpiresIn() {
        return expiresIn;
    }
    public void setExpiresIn(int expiresIn) {
        this.expiresIn = expiresIn;
    }
    public int getInterval() {
        return interval;
    }
    public void setInterval(int interval) {
        this.interval = interval;
    }
}

+ 2 - 1
server/svr-authentication/src/main/java/com/yihu/jw/security/model/Oauth2Envelop.java

@ -2,13 +2,14 @@ package com.yihu.jw.security.model;
import com.fasterxml.jackson.annotation.JsonInclude;
import java.io.Serializable;
import java.util.HashMap;
/**
 * Model - 认证失败信息
 * Created by progr1mmer on 2018/8/29.
 */
public class Oauth2Envelop<T> {
public class Oauth2Envelop<T> implements Serializable {
    protected String message;
    protected Integer status;

+ 31 - 0
server/svr-authentication/src/main/java/com/yihu/jw/security/model/PublicKey.java

@ -0,0 +1,31 @@
package com.yihu.jw.security.model;
import java.io.Serializable;
/**
 * Model 公钥
 * Created by progr1mmer on 2018/9/3.
 */
public class PublicKey implements Serializable {
    //模
    private String modulus;
    //指数
    private String exponent;
    public String getModulus() {
        return modulus;
    }
    public void setModulus(String modulus) {
        this.modulus = modulus;
    }
    public String getExponent() {
        return exponent;
    }
    public void setExponent(String exponent) {
        this.exponent = exponent;
    }
}

+ 19 - 5
server/svr-authentication/src/main/java/com/yihu/jw/security/oauth2/core/redis/WlyyRedisVerifyCodeService.java

@ -6,6 +6,7 @@ import org.springframework.util.StringUtils;
import java.util.concurrent.TimeUnit;
/**
 * Service - 验证码缓存
 * Created by progr1mmer on 2018/4/18.
 */
public class WlyyRedisVerifyCodeService {
@ -17,21 +18,34 @@ public class WlyyRedisVerifyCodeService {
        this.redisTemplate = redisTemplate;
    }
    public void store (String client_id, String username, String code, long expire) {
    public void store (String client_id, String username, String code, int expire) {
        String key = client_id + ":" + username + KEY_SUFFIX;
        redisTemplate.opsForValue().set(key, code);
        redisTemplate.expire(key, expire, TimeUnit.MILLISECONDS);
        redisTemplate.expire(key, expire, TimeUnit.SECONDS);
        String intervalKey = key + ":" + code + "_interval";
        redisTemplate.opsForValue().set(intervalKey, 60);
        redisTemplate.expire(intervalKey, 60, TimeUnit.SECONDS);
    }
    public Integer getExpireTime (String client_id, String username) {
        return new Long(redisTemplate.getExpire(client_id + ":" + username + KEY_SUFFIX)).intValue();
    public boolean isIntervalTimeout(String client_id, String username) {
        String key = client_id + ":" + username + KEY_SUFFIX;
        String code = (String) redisTemplate.opsForValue().get(key);
        if (null == code) {
            return true;
        }
        String intervalKey = key + ":" + code + "_interval";
        if (redisTemplate.opsForValue().get(intervalKey) != null) {
            return false;
        }
        return true;
    }
    public boolean verification (String client_id, String username, String code) {
        if (StringUtils.isEmpty(code)) {
            return false;
        }
        String _code = (String) redisTemplate.opsForValue().get(client_id + ":" + username + KEY_SUFFIX);
        String key = client_id + ":" + username + KEY_SUFFIX;
        String _code = (String) redisTemplate.opsForValue().get(key);
        if (null == _code) {
            return false;
        }

+ 27 - 38
server/svr-authentication/src/main/java/com/yihu/jw/security/oauth2/provider/WlyyTokenGranter.java

@ -37,38 +37,38 @@ public class WlyyTokenGranter implements TokenGranter {
                            OAuth2RequestFactory requestFactory,
                            WlyyRedisVerifyCodeService wlyyRedisVerifyCodeService) {
        tokenGranters.put(EhrAuthorizationCodeGranter.GRANT_TYPE,
                new EhrAuthorizationCodeGranter(
        tokenGranters.put(WlyyAuthorizationCodeGranter.GRANT_TYPE,
                new WlyyAuthorizationCodeGranter(
                        tokenServices,
                        authorizationCodeServices,
                        clientDetailsService,
                        requestFactory
                ));
        tokenGranters.put(EhrResourceOwnerPasswordTokenGranter.GRANT_TYPE,
                new EhrResourceOwnerPasswordTokenGranter(
        tokenGranters.put(WlyyResourceOwnerPasswordTokenGranter.GRANT_TYPE,
                new WlyyResourceOwnerPasswordTokenGranter(
                        authenticationManager,
                        tokenServices,
                        clientDetailsService,
                        requestFactory
                ));
        tokenGranters.put(EhrRefreshTokenGranter.GRANT_TYPE,
                new EhrRefreshTokenGranter(
        tokenGranters.put(WlyyRefreshTokenGranter.GRANT_TYPE,
                new WlyyRefreshTokenGranter(
                        tokenServices,
                        clientDetailsService,
                        requestFactory
                ));
        tokenGranters.put(EhrImplicitTokenGranter.GRANT_TYPE,
                new EhrImplicitTokenGranter(
        tokenGranters.put(WlyyImplicitTokenGranter.GRANT_TYPE,
                new WlyyImplicitTokenGranter(
                        tokenServices,
                        clientDetailsService,
                        requestFactory
                ));
        tokenGranters.put(EhrVerifyCodeTokenGranter.GRANT_TYPE,
                new EhrVerifyCodeTokenGranter(
        tokenGranters.put(WlyyCaptchaTokenGranter.GRANT_TYPE,
                new WlyyCaptchaTokenGranter(
                        authenticationManager,
                        tokenServices,
                        clientDetailsService,
@ -88,19 +88,19 @@ public class WlyyTokenGranter implements TokenGranter {
    /**
     * authorization_code模式Token授权器。
     */
    public static class EhrAuthorizationCodeGranter extends AbstractTokenGranter {
    public static class WlyyAuthorizationCodeGranter extends AbstractTokenGranter {
        public static final String GRANT_TYPE = "authorization_code";
        private final AuthorizationCodeServices authorizationCodeServices;
        public EhrAuthorizationCodeGranter(AuthorizationServerTokenServices tokenServices,
        public WlyyAuthorizationCodeGranter(AuthorizationServerTokenServices tokenServices,
                                           AuthorizationCodeServices authorizationCodeServices,
                                           ClientDetailsService clientDetailsService,
                                           OAuth2RequestFactory requestFactory) {
            this(tokenServices, authorizationCodeServices, clientDetailsService, requestFactory, GRANT_TYPE);
        }
        protected EhrAuthorizationCodeGranter(AuthorizationServerTokenServices tokenServices,
        protected WlyyAuthorizationCodeGranter(AuthorizationServerTokenServices tokenServices,
                                              AuthorizationCodeServices authorizationCodeServices,
                                              ClientDetailsService clientDetailsService,
                                              OAuth2RequestFactory requestFactory,
@ -162,17 +162,6 @@ public class WlyyTokenGranter implements TokenGranter {
            Authentication userAuth = storedAuth.getUserAuthentication();
            //再次通过pk获取当前请求的用户信息
            /*String pk = combinedParameters.get("pk");
            String keyId = ehrJDBCUserSecurityService.getDefaultKeyIdSelectStatement(pk);
            String userId = ehrJDBCUserSecurityService.getDefaultUserIdByKeyIdSelectStatement(keyId);
            String userName = ehrJDBCUserSecurityService.getDefaultUserNameByUserId(userId);
            UserDetails userDetails = ehrUserDetailsService.loadUserByUsername(userName);
            if (StringUtils.isEmpty(keyId) || StringUtils.isEmpty(userId) || StringUtils.isEmpty(userName)) {
                throw new InsufficientAuthenticationException("Illegal pk");
            }
            UsernamePasswordAuthenticationToken userToken = new UsernamePasswordAuthenticationToken(userDetails.getUsername(), userDetails.getPassword(), userDetails.getAuthorities());*/
            return new OAuth2Authentication(finalStoredOAuth2Request, userAuth);
        }
    }
@ -180,17 +169,17 @@ public class WlyyTokenGranter implements TokenGranter {
    /**
     * password模式Token授权器。
     */
    public static class EhrResourceOwnerPasswordTokenGranter extends AbstractTokenGranter {
    public static class WlyyResourceOwnerPasswordTokenGranter extends AbstractTokenGranter {
        private static final String GRANT_TYPE = "password";
        private final AuthenticationManager authenticationManager;
        public EhrResourceOwnerPasswordTokenGranter(AuthenticationManager authenticationManager,
        public WlyyResourceOwnerPasswordTokenGranter(AuthenticationManager authenticationManager,
                                                 AuthorizationServerTokenServices tokenServices, ClientDetailsService clientDetailsService, OAuth2RequestFactory requestFactory) {
            this(authenticationManager, tokenServices, clientDetailsService, requestFactory, GRANT_TYPE);
        }
        protected EhrResourceOwnerPasswordTokenGranter(AuthenticationManager authenticationManager, AuthorizationServerTokenServices tokenServices,
        protected WlyyResourceOwnerPasswordTokenGranter(AuthenticationManager authenticationManager, AuthorizationServerTokenServices tokenServices,
                                                    ClientDetailsService clientDetailsService, OAuth2RequestFactory requestFactory, String grantType) {
            super(tokenServices, clientDetailsService, requestFactory, grantType);
            this.authenticationManager = authenticationManager;
@ -230,10 +219,10 @@ public class WlyyTokenGranter implements TokenGranter {
    /**
     * refresh模式Token授权器。
     */
    public static class EhrRefreshTokenGranter extends AbstractTokenGranter {
    public static class WlyyRefreshTokenGranter extends AbstractTokenGranter {
        static final String GRANT_TYPE = "refresh_token";
        public EhrRefreshTokenGranter(AuthorizationServerTokenServices tokenServices,
        public WlyyRefreshTokenGranter(AuthorizationServerTokenServices tokenServices,
                                      ClientDetailsService clientDetailsService,
                                      OAuth2RequestFactory requestFactory) {
            super(tokenServices, clientDetailsService, requestFactory, GRANT_TYPE);
@ -250,14 +239,14 @@ public class WlyyTokenGranter implements TokenGranter {
    /**
     * Implicit模式Token授权器。
     */
    public static class EhrImplicitTokenGranter extends AbstractTokenGranter {
    public static class WlyyImplicitTokenGranter extends AbstractTokenGranter {
        private static final String GRANT_TYPE = "implicit";
        public EhrImplicitTokenGranter(AuthorizationServerTokenServices tokenServices, ClientDetailsService clientDetailsService, OAuth2RequestFactory requestFactory) {
        public WlyyImplicitTokenGranter(AuthorizationServerTokenServices tokenServices, ClientDetailsService clientDetailsService, OAuth2RequestFactory requestFactory) {
            this(tokenServices, clientDetailsService, requestFactory, GRANT_TYPE);
        }
        protected EhrImplicitTokenGranter(AuthorizationServerTokenServices tokenServices, ClientDetailsService clientDetailsService,
        protected WlyyImplicitTokenGranter(AuthorizationServerTokenServices tokenServices, ClientDetailsService clientDetailsService,
                                       OAuth2RequestFactory requestFactory, String grantType) {
            super(tokenServices, clientDetailsService, requestFactory, grantType);
        }
@ -285,14 +274,14 @@ public class WlyyTokenGranter implements TokenGranter {
    /**
     * verify_code模式Token授权器。
     */
    public static class EhrVerifyCodeTokenGranter extends AbstractTokenGranter {
        private static final String GRANT_TYPE = "verify_code";
    public static class WlyyCaptchaTokenGranter extends AbstractTokenGranter {
        private static final String GRANT_TYPE = "captcha";
        private final AuthenticationManager authenticationManager;
        // Ehr Properties
        private final WlyyRedisVerifyCodeService wlyyRedisVerifyCodeService;
        public EhrVerifyCodeTokenGranter(AuthenticationManager authenticationManager,
        public WlyyCaptchaTokenGranter(AuthenticationManager authenticationManager,
                                         AuthorizationServerTokenServices tokenServices,
                                         ClientDetailsService clientDetailsService,
                                         OAuth2RequestFactory requestFactory,
@ -300,7 +289,7 @@ public class WlyyTokenGranter implements TokenGranter {
            this(authenticationManager, tokenServices, clientDetailsService, requestFactory, GRANT_TYPE, wlyyRedisVerifyCodeService);
        }
        protected EhrVerifyCodeTokenGranter(AuthenticationManager authenticationManager,
        protected WlyyCaptchaTokenGranter(AuthenticationManager authenticationManager,
                                            AuthorizationServerTokenServices tokenServices,
                                            ClientDetailsService clientDetailsService,
                                            OAuth2RequestFactory requestFactory,
@ -317,10 +306,10 @@ public class WlyyTokenGranter implements TokenGranter {
            Map<String, String> parameters = new LinkedHashMap<String, String>(tokenRequest.getRequestParameters());
            String client_id = parameters.get("client_id");
            String username = parameters.get("username");
            String verify_code = parameters.get("verify_code");
            String verify_code = parameters.get("captcha");
            if (!wlyyRedisVerifyCodeService.verification(client_id, username, verify_code)){
                throw new InvalidGrantException("Invalid verify_code");
                throw new InvalidGrantException("Invalid captcha");
            }
            Authentication userAuth = new UsernamePasswordAuthenticationToken(username, verify_code, getGrantedAuthorities(username));
            ((AbstractAuthenticationToken) userAuth).setDetails(parameters);

+ 158 - 107
server/svr-authentication/src/main/java/com/yihu/jw/security/oauth2/provider/endpoint/WlyyLoginEndpoint.java

@ -1,18 +1,19 @@
package com.yihu.jw.security.oauth2.provider.endpoint;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.yihu.jw.security.model.Captcha;
import com.yihu.jw.security.model.PublicKey;
import com.yihu.jw.security.oauth2.core.redis.WlyyRedisVerifyCodeService;
import com.yihu.jw.security.oauth2.provider.error.WlyyOAuth2ExceptionTranslator;
import com.yihu.jw.security.oauth2.provider.WlyyTokenGranter;
import com.yihu.jw.security.core.userdetails.jdbc.WlyyUserDetailsService;
import com.yihu.jw.security.model.Oauth2Envelop;
import com.yihu.jw.security.model.WlyyUserSimple;
import com.yihu.utils.security.RSAUtils;
import org.apache.commons.codec.binary.Base64;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.http.*;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
@ -24,15 +25,27 @@ import org.springframework.security.oauth2.provider.request.DefaultOAuth2Request
import org.springframework.security.oauth2.provider.request.DefaultOAuth2RequestValidator;
import org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStore;
import org.springframework.util.Assert;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.annotation.PostConstruct;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
/**
 * <p>
@ -64,26 +77,36 @@ public class WlyyLoginEndpoint extends AbstractEndpoint {
    @Autowired
    private WlyyUserDetailsService userDetailsService;
    @Autowired
    private WlyyRedisVerifyCodeService wlyyRedisVerifyCodeService;
    private RestTemplate restTemplate;
    @Autowired
    private ObjectMapper objectMapper;
    private WlyyRedisVerifyCodeService wlyyRedisVerifyCodeService;
    @PostConstruct
    private void init() {
        super.setTokenGranter(tokenGranter);
    }
    /**
     * 登陆
     * @param parameters
     * @param httpSession
     * @return
     * @throws Exception
     */
    @RequestMapping(value = "/oauth/login", method = RequestMethod.POST)
    public ResponseEntity<Oauth2Envelop<WlyyUserSimple>> login(@RequestParam Map<String, String> parameters) {
    public ResponseEntity<Oauth2Envelop<WlyyUserSimple>> login(@RequestParam Map<String, String> parameters, HttpSession httpSession) throws Exception {
        String client_id = parameters.get("client_id");
        if (StringUtils.isEmpty(client_id)) {
            throw new InvalidRequestException("client_id");
        }
        if (StringUtils.isEmpty(parameters.get("verify_code"))) {
        if (StringUtils.isEmpty(parameters.get("captcha"))) {
            parameters.put("grant_type", "password");
            if (parameters.get("password") != null) {
                RSAPrivateKey rsaPrivateKey = (RSAPrivateKey)httpSession.getAttribute("privateKey");
                parameters.put("password", RSAUtils.decryptByPrivateKey(new String(Base64.decodeBase64(parameters.get("password"))), rsaPrivateKey));
            }
        } else {
            parameters.put("grant_type", "verify_code");
            parameters.put("grant_type", "captcha");
        }
        ClientDetails authenticatedClient = clientDetailsService.loadClientByClientId(client_id);
@ -118,6 +141,11 @@ public class WlyyLoginEndpoint extends AbstractEndpoint {
        return getResponse(wlyyUserSimple);
    }
    /**
     * 单点登陆第二步 - token验证
     * @param parameters
     * @return
     */
    @RequestMapping(value = "/oauth/sso", method = RequestMethod.POST)
    public ResponseEntity<Oauth2Envelop<WlyyUserSimple>> sso(@RequestParam Map<String, String> parameters) {
        String clientId = parameters.get("client_id");
@ -154,6 +182,12 @@ public class WlyyLoginEndpoint extends AbstractEndpoint {
        return getResponse(wlyyUserSimple);
    }
    /**
     * 登出
     * @param parameters
     * @param request
     * @return
     */
    @RequestMapping(value = "/oauth/logout", method = RequestMethod.POST)
    public ResponseEntity<Oauth2Envelop> logout(@RequestParam Map<String, String> parameters, HttpServletRequest request) {
        String token = request.getHeader("token");
@ -172,112 +206,125 @@ public class WlyyLoginEndpoint extends AbstractEndpoint {
        return new ResponseEntity<>(oauth2Envelop, headers, HttpStatus.OK);
    }
    /*@RequestMapping(value = ServiceApi.Authentication.VerifyCode, method = RequestMethod.POST)
    public ResponseEntity<Envelop> verifyCode(@RequestParam Map<String, String> parameters) throws  Exception{
        Envelop envelop = new Envelop();
    /**
     * 获取公钥
     * @param httpSession
     * @param httpServletResponse
     * @return
     * @throws Exception
     */
    @RequestMapping(value = "/oauth/public_key", method = RequestMethod.GET)
    public ResponseEntity<Oauth2Envelop<PublicKey>> publicKey (
            HttpSession httpSession,
            HttpServletResponse httpServletResponse) throws Exception {
        //生成公钥和私钥
        HashMap<String, Object> map = RSAUtils.generateKeys();
        RSAPublicKey rsaPublicKey = (RSAPublicKey) map.get("public");
        RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) map.get("private");
        PublicKey publicKey = new PublicKey();
        publicKey.setModulus(Base64.encodeBase64String(rsaPublicKey.getModulus().toByteArray()));
        publicKey.setExponent(Base64.encodeBase64String(rsaPublicKey.getPublicExponent().toByteArray()));
        httpSession.setAttribute("privateKey", rsaPrivateKey);
        //生成Cookie
        Cookie cookie = new Cookie("oauth2", UUID.randomUUID().toString());
        cookie.setMaxAge(60);
        cookie.setPath("/oauth");
        httpServletResponse.addCookie(cookie);
        HttpHeaders headers = new HttpHeaders();
        headers.set("Cache-Control", "no-store");
        headers.set("Pragma", "no-cache");
        Oauth2Envelop<PublicKey> oauth2Envelop = new Oauth2Envelop<>("public_key", 200, publicKey);
        return new ResponseEntity<>(oauth2Envelop, headers, HttpStatus.OK);
    }
    /**
     * 获取验证码
     * @param parameters
     * @return
     * @throws Exception
     */
    @RequestMapping(value = "/oauth/captcha", method = RequestMethod.GET)
    public ResponseEntity<Oauth2Envelop<Captcha>> captcha(@RequestParam Map<String, String> parameters) throws  Exception{
        String client_id = parameters.get("client_id");
        String username = parameters.get("username");
        if (StringUtils.isEmpty(client_id)) {
            throw new InvalidRequestException("client_id");
        }
        if (StringUtils.isEmpty(username)){
            envelop.setSuccessFlg(false);
            envelop.setErrorMsg("手机号码【"+username+"】不能为空!");
            return new ResponseEntity<>(envelop, headers, HttpStatus.OK);
            throw new InvalidRequestException("username");
        }
        VerifyCode verifyCode = new VerifyCode();
        //手机短信验证码
        RandomUtil randomUtil = new RandomUtil();
        String random = randomUtil.getRandomString(6);
        //发送短信
        String api = "MsgGW.Sms.send";
        String content = "尊敬的用户:欢迎使用健康上饶,您的验证码为:【" + random + "】,有效期10分钟,请尽快完成注册。若非本人操作,请忽略。";
        Map<String, String> apiParamMap = new HashMap<>();
        //手机号码
        apiParamMap.put("mobile", username);
        //业务标签
        apiParamMap.put("handlerId", fzHandlerId);
        //短信内容
        apiParamMap.put("content", content);
        //渠道号
        apiParamMap.put("clientId", fzClientId);
        String result = null;
        Envelop resultEnvelop = fzApiClient.fzInnerApi(api, objectMapper.writeValueAsString(apiParamMap), 1);
        if (resultEnvelop.isSuccessFlg()) {
            result = resultEnvelop.getObj().toString();
        //验证请求间隔超时,防止频繁获取验证码
        if (!wlyyRedisVerifyCodeService.isIntervalTimeout(client_id, username)) {
            throw new IllegalAccessException("SMS request frequency is too fast");
        }
        if (!StringUtils.isEmpty(result)) {
            Map<String, Object> resultMap = objectMapper.readValue(result, Map.class);
            Integer resultCode = 0;
            if (null != resultMap.get("Code") && !"".equals(resultMap.get("Code"))) {
                resultCode = Integer.valueOf(resultMap.get("Code").toString());
            }
            if (resultCode == 10000) {
                verifyCode.setExpiresIn(600);
                verifyCode.setNextRequestTime(60);
                //验证码有效期
                ehrRedisVerifyCodeService.store(client_id, username, random, 600000);
                envelop.setSuccessFlg(true);
                envelop.setObj(verifyCode);
            } else if(resultCode == -201){
                envelop.setSuccessFlg(false);
                envelop.setErrorCode(resultCode);
                envelop.setErrorMsg("短信已达每天限制的次数(10次)!");
            } else if(resultCode == -200){
                envelop.setSuccessFlg(false);
                envelop.setErrorCode(resultCode);
                envelop.setErrorMsg("短信发送频率太快(不能低于60s)!");
            } else {
                envelop.setSuccessFlg(false);
                envelop.setErrorCode(resultCode);
                envelop.setErrorMsg("短信验证码发送失败!");
            }
        } else {
            envelop.setSuccessFlg(false);
            envelop.setErrorCode(ErrorCode.REQUEST_NOT_COMPLETED.value());
            envelop.setErrorMsg("短信验证码发送失败!");
        //发送短信获取验证码
        HttpHeaders reqHeaders = new HttpHeaders();
        reqHeaders.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
        MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
        params.add("clientId", client_id);
        params.add("type", "login");
        params.add("to", username);
        HttpEntity<MultiValueMap<String, String>> httpEntity = new HttpEntity<>(params, reqHeaders);
        HashMap<String, Object> result = restTemplate.postForObject("http://svr-base:10020/sms_gateway/send", httpEntity, HashMap.class);
        if (200 == (Integer) result.get("status")){
            Map<String, Object> sms =  (Map)result.get("obj");
            String captcha = (String) sms.get("captcha");
            Date deadline = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse((String) sms.get("deadline"));
            Long expire = (deadline.getTime() - new Date().getTime()) / 1000;
            Captcha _captcha = new Captcha();
            _captcha.setCode(captcha);
            _captcha.setExpiresIn(expire.intValue());
            wlyyRedisVerifyCodeService.store(client_id, username, captcha, expire.intValue());
            Oauth2Envelop<Captcha> oauth2Envelop = new Oauth2Envelop<>("captcha", 200, _captcha);
            HttpHeaders headers = new HttpHeaders();
            headers.set("Cache-Control", "no-store");
            headers.set("Pragma", "no-cache");
            return new ResponseEntity<>(oauth2Envelop, headers, HttpStatus.OK);
        }
        return new ResponseEntity<>(envelop, headers, HttpStatus.OK);
    }
    @RequestMapping(value = ServiceApi.Authentication.VerifyCodeExpire, method = RequestMethod.POST)
    public ResponseEntity<VerifyCode> verifyCodeExpire(@RequestParam Map<String, String> parameters) {
        String client_id = parameters.get("client_id");
        String username = parameters.get("username");
        VerifyCode verifyCode = new VerifyCode();
        int expiresIn = ehrRedisVerifyCodeService.getExpireTime(client_id, username);
        int nextRequestTime = 60 + (expiresIn - 600 ) > 0 ? 60 + (expiresIn - 600 ) : 0;
        verifyCode.setNextRequestTime(nextRequestTime);
        verifyCode.setExpiresIn(expiresIn);
        throw new IllegalStateException((String) result.get("message"));
        /*Captcha _captcha = new Captcha();
        _captcha.setCode("12345");
        _captcha.setExpiresIn(10000);
        _captcha.setInterval(60);
        wlyyRedisVerifyCodeService.store(client_id, username, "12345", 100);
        Oauth2Envelop<Captcha> oauth2Envelop = new Oauth2Envelop("captcha", 200, _captcha);
        HttpHeaders headers = new HttpHeaders();
        headers.set("Cache-Control", "no-store");
        headers.set("Pragma", "no-cache");
        return new ResponseEntity<>(verifyCode, headers, HttpStatus.OK);
        return new ResponseEntity<>(oauth2Envelop, headers, HttpStatus.OK);*/
    }
    @RequestMapping(value = ServiceApi.Authentication.VerifyCodeValidate, method = RequestMethod.POST)
    public ResponseEntity<Envelop> verifyCodeValidate(@RequestParam Map<String, String> parameters) throws  Exception{
        Envelop envelop = new Envelop();
        HttpHeaders headers = new HttpHeaders();
        headers.set("Cache-Control", "no-store");
        headers.set("Pragma", "no-cache");
    /**
     * 验证验证码
     * @param parameters
     * @return
     * @throws Exception
     */
    @RequestMapping(value = "/oauth/captcha", method = RequestMethod.POST)
    public ResponseEntity<Oauth2Envelop> captchaCheck  (@RequestParam Map<String, String> parameters) throws  Exception{
        String client_id = parameters.get("client_id");
        String username = parameters.get("username");
        String verifyCode = parameters.get("verify_code");
        if (StringUtils.isEmpty(verifyCode)){
            envelop.setSuccessFlg(false);
            envelop.setErrorMsg("验证码不能为空!");
            return new ResponseEntity<>(envelop, headers, HttpStatus.OK);
        String captcha = parameters.get("captcha");
        if (StringUtils.isEmpty(client_id)) {
            throw new InvalidRequestException("client_id");
        }
        boolean _verify = ehrRedisVerifyCodeService.verification(client_id, username, verifyCode);
        if (_verify){
            envelop.setSuccessFlg(true);
        if (StringUtils.isEmpty(username)){
            throw new InvalidRequestException("username");
        }
        if (StringUtils.isEmpty(captcha)){
            throw new InvalidRequestException("captcha");
        }
        Oauth2Envelop<Boolean> oauth2Envelop;
        if (wlyyRedisVerifyCodeService.verification(client_id, username, captcha)) {
            oauth2Envelop = new Oauth2Envelop<>("验证码正确", 200, true);
        } else {
            envelop.setSuccessFlg(false);
            envelop.setErrorMsg("请输入正确的验证码!");
            oauth2Envelop = new Oauth2Envelop<>("验证码错误", 200, false);
        }
        return new ResponseEntity<>(envelop, headers, HttpStatus.OK);
    }*/
        HttpHeaders headers = new HttpHeaders();
        headers.set("Cache-Control", "no-store");
        headers.set("Pragma", "no-cache");
        return new ResponseEntity<>(oauth2Envelop, headers, HttpStatus.OK);
    }
    @Override
    protected TokenGranter getTokenGranter() {
@ -308,27 +355,31 @@ public class WlyyLoginEndpoint extends AbstractEndpoint {
    public ResponseEntity<Oauth2Envelop> handleException(Exception e) throws Exception {
        LOG.info(e.getMessage(), e);
        if (e instanceof UsernameNotFoundException) {
            return handleOAuth2Exception(new Oauth2Envelop("用户未注册!", HttpStatus.UNAUTHORIZED.value()));
            return handleOAuth2Exception(new Oauth2Envelop("用户未注册!", HttpStatus.UNAUTHORIZED.value()), e);
        } else if (e instanceof NoSuchClientException) {
            return handleOAuth2Exception(new Oauth2Envelop("应用未注册!", HttpStatus.UNAUTHORIZED.value()));
            return handleOAuth2Exception(new Oauth2Envelop("应用未注册!", HttpStatus.UNAUTHORIZED.value()), e);
        } else if (e instanceof InvalidGrantException) {
            if (e.getMessage().equals("verify_code")) {
                return handleOAuth2Exception(new Oauth2Envelop("验证码有误!", HttpStatus.UNAUTHORIZED.value()));
            if (e.getMessage().contains("captcha")) {
                return handleOAuth2Exception(new Oauth2Envelop("验证码有误!", HttpStatus.UNAUTHORIZED.value()), e);
            }
            return handleOAuth2Exception(new Oauth2Envelop("密码有误!", HttpStatus.UNAUTHORIZED.value()));
            return handleOAuth2Exception(new Oauth2Envelop("密码有误!", HttpStatus.UNAUTHORIZED.value()), e);
        } else if (e instanceof InvalidTokenException) {
            return handleOAuth2Exception(new Oauth2Envelop("Token有误!", HttpStatus.UNAUTHORIZED.value()));
            return handleOAuth2Exception(new Oauth2Envelop("Token有误!", HttpStatus.UNAUTHORIZED.value()), e);
        } else if (e instanceof InvalidRequestException) {
            return handleOAuth2Exception(new Oauth2Envelop("参数" + e.getMessage() + "缺失!", HttpStatus.UNAUTHORIZED.value()));
            return handleOAuth2Exception(new Oauth2Envelop("参数" + e.getMessage() + "缺失!", HttpStatus.UNAUTHORIZED.value()), e);
        } else if (e instanceof IllegalAccessException) {
            return handleOAuth2Exception(new Oauth2Envelop("短信请求频率过快,请稍后再试!", -1), e);
        } else if (e instanceof IllegalStateException) {
            return handleOAuth2Exception(new Oauth2Envelop("短信网关请求失败!", -1), e);
        }
        return handleOAuth2Exception(new Oauth2Envelop(e.getMessage(), -1));
        return handleOAuth2Exception(new Oauth2Envelop(e.getMessage(), -1), e);
    }
    private ResponseEntity<Oauth2Envelop> handleOAuth2Exception(Oauth2Envelop authenticationFailed) throws IOException {
    private ResponseEntity<Oauth2Envelop> handleOAuth2Exception(Oauth2Envelop authenticationFailed, Exception e) throws IOException {
        HttpHeaders headers = new HttpHeaders();
        headers.set("Cache-Control", "no-store");
        headers.set("Pragma", "no-cache");
        headers.set("WWW-Authenticate", String.format("%s %s", OAuth2AccessToken.BEARER_TYPE, authenticationFailed.getMessage()));
        headers.set("WWW-Authenticate", String.format("%s %s", OAuth2AccessToken.BEARER_TYPE, e.getMessage()));
        ResponseEntity<Oauth2Envelop> response = new ResponseEntity<>(authenticationFailed, headers, HttpStatus.OK);
        return response;
    }

+ 5 - 8
server/svr-authentication/src/main/java/com/yihu/jw/security/oauth2/provider/endpoint/WlyyTokenEndpoint.java

@ -97,7 +97,6 @@ public class WlyyTokenEndpoint extends AbstractEndpoint {
        TokenRequest tokenRequest = getOAuth2RequestFactory().createTokenRequest(parameters, authenticatedClient);
        /*
         * customize
         * skip this step
         */
        /*if (clientId != null && !clientId.equals("")) {
@ -136,7 +135,7 @@ public class WlyyTokenEndpoint extends AbstractEndpoint {
        if (token == null) {
            throw new UnsupportedGrantTypeException("Unsupported grant type: " + tokenRequest.getGrantType());
        }
        // customize ---------------------------------
        // ----------------- Simple Result ----------------
        WlyyOAuth2AccessToken wlyyOAuth2AccessToken = new WlyyOAuth2AccessToken();
        wlyyOAuth2AccessToken.setAccessToken(token.getValue());
        wlyyOAuth2AccessToken.setTokenType(token.getTokenType());
@ -144,7 +143,7 @@ public class WlyyTokenEndpoint extends AbstractEndpoint {
        wlyyOAuth2AccessToken.setRefreshToken(token.getRefreshToken().getValue());
        wlyyOAuth2AccessToken.setScope(org.apache.commons.lang.StringUtils.join(token.getScope(), " "));
        wlyyOAuth2AccessToken.setState(parameters.get("state"));
        // customize ---------------------------------
        // ----------------- Simple Result ----------------
        return getResponse(wlyyOAuth2AccessToken);
@ -201,7 +200,6 @@ public class WlyyTokenEndpoint extends AbstractEndpoint {
    }*/
    /**
     * (customize)
     * @param e
     * @return
     * @throws Exception
@ -209,7 +207,7 @@ public class WlyyTokenEndpoint extends AbstractEndpoint {
    @ExceptionHandler(Exception.class)
    public ResponseEntity<Oauth2Envelop> handleException(Exception e) throws Exception {
        LOG.info(e.getMessage(), e);
        return handleOAuth2Exception(new Oauth2Envelop(e.getMessage(), -1));
        return handleOAuth2Exception(new Oauth2Envelop(e.getMessage(), -1), e);
    }
    private ResponseEntity<WlyyOAuth2AccessToken> getResponse(WlyyOAuth2AccessToken accessToken) {
@ -220,17 +218,16 @@ public class WlyyTokenEndpoint extends AbstractEndpoint {
    }
    /**
     * customize
     * return results directly
     * @param authenticationFailed
     * @return
     * @throws IOException
     */
    private ResponseEntity<Oauth2Envelop> handleOAuth2Exception(Oauth2Envelop authenticationFailed) throws IOException {
    private ResponseEntity<Oauth2Envelop> handleOAuth2Exception(Oauth2Envelop authenticationFailed, Exception e) throws IOException {
        HttpHeaders headers = new HttpHeaders();
        headers.set("Cache-Control", "no-store");
        headers.set("Pragma", "no-cache");
        headers.set("WWW-Authenticate", String.format("%s %s", OAuth2AccessToken.BEARER_TYPE, authenticationFailed.getMessage()));
        headers.set("WWW-Authenticate", String.format("%s %s", OAuth2AccessToken.BEARER_TYPE, e.getMessage()));
        ResponseEntity<Oauth2Envelop> response = new ResponseEntity<>(authenticationFailed, headers, HttpStatus.OK);
        return response;
    }