コード例 #1
0
        public Task <IActionResult> Challenge(string provider, string returnUrl)
        {
            if (string.IsNullOrEmpty(returnUrl))
            {
                returnUrl = "~/";
            }

            // validate returnUrl - either it is a valid OIDC URL or back to a local page
            if (Url.IsLocalUrl(returnUrl) == false)
            {
                // user might have clicked on a malicious link - should be logged
                throw ApiException.Common(RequestLocalizer["Invalid return URL"]);
            }

            // start challenge and roundtrip the return URL and scheme
            var props = new AuthenticationProperties
            {
                RedirectUri = Url.Action(nameof(Callback)),
                //RedirectUri = returnUrl,
                Items =
                {
                    { "returnUrl", returnUrl },
                    { "scheme",    provider  },
                }
            };

            return(Task.FromResult((IActionResult)Challenge(props, provider)));
        }
コード例 #2
0
        public ApiResult <bool> ChangePassword(RequestPassword model)
        {
            IUser user;

            switch (model.Type)
            {
            case 0:
                user = ApplicationUser.FindByName(model.UserName);
                CheckUser(user);
                if (user.Password != model.OldPassword.MD5())
                {
                    throw ApiException.Common(RequestLocalizer["The old password is incorrect"]);
                }
                break;

            case 1:
                user = ApplicationUser.FindByMobile(model.Mobile);
                CheckUser(user);
                if (!CheckVerCode(model.InternationalAreaCode + model.Mobile, model.VerCode, 0))
                {
                    throw ApiException.Common(RequestLocalizer["The verification code is incorrect or expired"]);
                }

                if (user.Mobile != model.Mobile)
                {
                    throw ApiException.Common(RequestLocalizer["Incorrect mobile phone number"]);
                }
                break;

            case 2:
                user = ApplicationUser.FindByMail(model.Mail);
                CheckUser(user);
                if (!CheckVerCode(model.Mail, model.VerCode, 1))
                {
                    throw ApiException.Common(RequestLocalizer["The verification code is incorrect or expired"]);
                }

                if (user.Mail != model.Mail)
                {
                    throw ApiException.Common(RequestLocalizer["Incorrect email address"]);
                }
                break;

            default:
                throw ApiException.Common("Type类型不正确!");
            }

            void CheckUser(IUser u)
            {
                if (u == null)
                {
                    throw ApiException.Common(RequestLocalizer["The user was not found"]);
                }
            }

            user.Password = model.NewPassword;
            user.Save();

            return(ApiResult.Ok(true));
        }
コード例 #3
0
        public async Task Handle(ExternalSignInContext externalSignInContext)
        {
            var properties            = externalSignInContext.AuthenticationProperties;
            var clientFactory         = externalSignInContext.HttpClientFactory;
            var requestLocalizer      = externalSignInContext.RequestLocalizer;
            var externalSignInHandler = externalSignInContext.Context;
            var user            = externalSignInContext.User;
            var requestServices = externalSignInContext.RequestServices;
            var providerKey     = properties.Items["providerKey"];

            // 首先获取OpenId
            var openIdEndpoint = QueryHelpers.AddQueryString(QQDefaults.OpenIdEndpoint,
                                                             "access_token", providerKey);
            var backchannel = clientFactory.CreateClient();

            var openIdResponse = await backchannel.GetAsync(openIdEndpoint);

            var openIdContent = await openIdResponse.Content.ReadAsStringAsync();

            openIdContent = openIdContent.TrimStart("callback( ").TrimEnd(" );\n");
            var openIdPayload = JObject.Parse(openIdContent);

            // 存储openid,绑定到系统的用户,作为系统在第三方的唯一标识
            var openId   = openIdPayload["openid"].Value <string>();
            var clientId = openIdPayload["client_id"].Value <string>();
            var tokenRequestParameters = new Dictionary <string, string>()
            {
                { "access_token", providerKey },
                { "oauth_consumer_key", clientId },
                { "openid", openId },
            };
            var endpoint = QueryHelpers.AddQueryString(QQDefaults.UserInformationEndpoint, tokenRequestParameters);

            var requestMessage = new HttpRequestMessage(HttpMethod.Get, endpoint);

            requestMessage.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
            var response = await backchannel.SendAsync(requestMessage);

            var userInfoPayload = JsonDocument.Parse(await response.Content.ReadAsStringAsync());

            var ret = userInfoPayload.RootElement.GetString("ret").ToInt();

            if (ret < 0)
            {
                throw ApiException.Common(requestLocalizer[userInfoPayload.RootElement.GetString("msg")]);
            }

            var options = requestServices.GetRequiredService <IOptionsMonitor <QQOptions> >().CurrentValue;

            var identity = user.Identity as ClaimsIdentity;

            externalSignInHandler.RunClaimActions(options.ClaimActions, identity, userInfoPayload.RootElement);

            identity?.AddClaim(new Claim(OAuthSignInAuthenticationDefaults.Sub, openId));
        }
コード例 #4
0
        public virtual async Task <SignInResult> LoginAsync(IUser user, string password, bool rememberMe = false)
        {
            if (!(user is TUser u))
            {
                throw ApiException.Common(_requestLocalizer["The user was not found"]);
            }

            var result = await _signInManager.PasswordSignInAsync(u, password, rememberMe, false);

            return(result);
        }
コード例 #5
0
        public virtual async Task <SignInResult> LoginAsync(IUser user)
        {
            if (!(user is TUser u))
            {
                throw ApiException.Common(_requestLocalizer["The user was not found"]);
            }

            await _signInManager.SignInAsync(u, false);

            return(SignInResult.Success);
        }
コード例 #6
0
        /// <summary>
        /// 获取过期时间
        /// </summary>
        /// <param name="token"></param>
        /// <returns></returns>
        private DateTime GetExpire(string token)
        {
            token = token.Replace("Bearer ", "", StringComparison.OrdinalIgnoreCase);
            var jwtToken = new JwtSecurityTokenHandler().ReadJwtToken(token);
            var exp      = jwtToken.Claims.FirstOrDefault(f => f.Type == "exp");

            if (exp == null)
            {
                throw ApiException.Common(_requestLocalizer["Could not find the exp claim in token"], 500);
            }

            var d = new DateTime(1970, 1, 1, 0, 0, 0, DateTime.Now.Kind).AddSeconds(exp.Value.ToInt());

            return(d);
        }
コード例 #7
0
        public virtual Task DeleteAccountAsync(IUser user)
        {
            XTrace.WriteLine($"删除用户信息:{(user as TUser)}");

            if (user == null || user.ID < 1)
            {
                throw ApiException.Common(_requestLocalizer["The user was not found"]);
            }

            (user as TUser)?.Delete();
            var ucs = UserConnect.FindAllByUserID(user.ID);

            ucs.Delete();

            return(Task.CompletedTask);
        }
コード例 #8
0
        public ApiResult <ResponseUserInfo> GetUserInfo()
        {
            //var principal = User;
            var identity = User.Identity as IUser;

            if (identity == null)
            {
                throw ApiException.Common(RequestLocalizer["User type error"], 500);
            }

            var data = new ResponseUserInfo();

            data.Copy(identity, false, "Roles");
            data.SetRoles(identity.Roles);

            return(ApiResult.Ok(data));
        }
コード例 #9
0
        protected override async Task <AuthenticateResult> HandleAuthenticateAsync()
        {
            // 认证之前检查Cookie中是否携带Token,有则设置头部的Authorization
            var authorization = "Authorization";

            if (!Request.Headers.ContainsKey(authorization) && Request.Cookies.TryGetValue("Admin-Token", out var token))
            {
                Request.Headers.Add(authorization, token);
            }
            else
            {
                token = Request.Headers[authorization];
            }

            if (token.IsNullOrWhiteSpace())
            {
                return(AuthenticateResult.NoResult());
            }

            var uc = CheckLocalRecord(token);

            if (uc != null)
            {
                return(uc.Expire < DateTime.Now ? AuthenticateResult.Fail(_requestLocalizer["No login or login timeout"])
                    : GetAuthenticateResult(uc));
            }

            // 登录记录不存在,请求授权中心
            var result = await Authenticate(token);

            if (result == null)
            {
                XTrace.WriteLine("请求授权中心失败");
                throw ApiException.Common("Request authorization center failed", 500);
            }

            if (result.Status != 0)
            {
                XTrace.WriteLine($"IAM中心请求认证结果异常:{result.ToJson()}");
                throw ApiException.Common(result.Msg, result.Status);
            }

            XTrace.WriteLine($"IAM中心请求认证后本地记录:{result.ToJson()}\\s\ntoken: {token}");

            return(await LocalSignIn(result.Data, token));
        }
コード例 #10
0
        public override ApiResult <string> Post(ApplicationUser value)
        {
            var exists = ApplicationUser.FindByName(value.Name) != null;

            if (exists)
            {
                throw ApiException.Common(RequestLocalizer["User already exists"]);
            }

            // 新增账号默认密码123456
            if (value.Password.IsNullOrWhiteSpace())
            {
                value.Password = "******".MD5();
            }

            return(base.Post(value));
        }
コード例 #11
0
        public ApiResult <string> UnbindOAuth([FromQuery] string id)
        {
            var uc = UserConnect.FindByKey(id);

            if (uc == null)
            {
                throw ApiException.Common(RequestLocalizer["Data not found"]);
            }

            if (!IsSupperAdmin && uc.UserID != AppUser.ID)
            {
                throw ApiException.Common(RequestLocalizer["No permission"]);
            }

            uc.Delete();

            return(ApiResult.Ok());
        }
コード例 #12
0
        /// <summary>
        /// 处理请求参数
        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        protected async Task HandleRequestAsync(HttpContext context)
        {
            SetAuthorization(context);

            var req = context.Request;

            var restRequest = new RestRequest(Path, DataFormat.Json);

            if (Enum.TryParse(req.Method, true, out Method method))
            {
                restRequest.Method = method;
            }

            if (req.Query.Any())
            {
                foreach (var(key, value) in req.Query)
                {
                    restRequest.AddQueryParameter(key, value);
                }
            }

            if (req.ContentLength != null)
            {
                var b = new byte[req.ContentLength.Value];

                var total = await req.Body.ReadAsync(b);

                var s = Encoding.UTF8.GetString(b);
                if (!s.IsNullOrWhiteSpace())
                {
                    Body = JObject.Parse(s);
                    restRequest.AddJsonBody(Body);
                }
            }

            RestResponse = await _restClient.ExecuteAsync(restRequest);

            // 判断是否有异常
            if (RestResponse.ErrorException != null)
            {
                XTrace.WriteException(RestResponse.ErrorException);
                throw ApiException.Common("The IAM Server is not available", 500);
            }
        }
コード例 #13
0
        /// <summary>
        /// 向IAM中心请求认证
        /// </summary>
        /// <param name="token"></param>
        /// <returns></returns>
        private async Task <ApiResult <ResponseUserInfo> > Authenticate(string token)
        {
            var restClient = new RestClient(Options.Url);

            restClient.AddDefaultHeader("Authorization", token);
            var path         = "/api/Account/GetUserInfo";
            var restRequest  = new RestRequest(path);
            var restResponse = await restClient.ExecuteAsync(restRequest);

            if (restResponse.StatusCode != HttpStatusCode.OK)
            {
                XTrace.WriteLine(restResponse.Content.ToJson());
                throw ApiException.Common(_requestLocalizer["Server error"], 500);
            }

            var result = JsonConvert.DeserializeObject <ApiResult <ResponseUserInfo> >(restResponse.Content);

            return(result);
        }
コード例 #14
0
        /// <summary>
        /// 更新用户信息
        /// </summary>
        /// <param name="dic"></param>
        /// <returns></returns>
        public virtual async Task UpdateAsync(IDictionary <string, object> dic)
        {
            var user = new TUser();

            foreach (var(key, value) in dic)
            {
                if (value == null)
                {
                    continue;                // 空值表示不改变
                }
                user.SetItem(key, value);
            }

            var result = await _userManager.UpdateAsync(user);

            if (!result.Succeeded)
            {
                throw ApiException.Common(_requestLocalizer[result.Errors.ToArray()[0].Code]);
            }
        }
コード例 #15
0
        private async Task SaveToken(string content)
        {
            var jwtTokenResult = JsonConvert.DeserializeObject <ApiResult <JwtToken> >(content);

            if (jwtTokenResult.Status != 0)
            {
                throw ApiException.Common(jwtTokenResult.Msg);
            }

            var jwtToken = jwtTokenResult.Data;

            var idp      = "IdentityServer4";
            var userInfo = jwtToken.UserInfo;

            if (userInfo == null)
            {
                throw ApiException.Common("登录返回的UserInfo不能为空", 500);
            }

            var u = await UpdateUserAsync(userInfo);

            var uc = UserConnect.FindByProviderAndOpenID(idp, userInfo.Name) ?? new UserConnect
            {
                Provider = idp,
                UserID   = u.ID,
                OpenID   = userInfo.Name,
                LinkID   = userInfo.ID.ToInt(),
                Enable   = true
            };

            uc.AccessToken = jwtToken.Token;
            uc.Avatar      = userInfo.Avatar;
            uc.NickName    = userInfo.DisplayName;
            uc.Expire      = jwtToken.Expires ?? GetExpire(jwtToken.Token);

            // 下面这两个防止uc没有删除导致再次注册时,id换了但还是以前的记录
            uc.UserID = u.ID;
            uc.LinkID = userInfo.ID.ToInt();

            uc.Save();
        }
コード例 #16
0
        public async Task <ApiResult <string> > Error(string errorId)
        {
            // retrieve error details from identityserver
            var message = await _interaction.GetErrorContextAsync(errorId);

            if (message != null)
            {
                if (!_environment.IsDevelopment())
                {
                    // only show in development
                    message.ErrorDescription = null;
                }

                XTrace.WriteLine($"授权出错:{message.Error}。描述:{message.ErrorDescription}");

                throw ApiException.Common(message.Error, 402);
            }
            else
            {
                return(ApiResult <string> .Ok("没有错误,但是跳到了'/home/error'这里"));
            }
        }
コード例 #17
0
        public async Task <ApiResult <bool> > UpdateUserInfo(RequestUserInfo userInfo)
        {
            if (userInfo.ID < 1)
            {
                throw ApiException.Common(RequestLocalizer["Incorrect ID"]);
            }

            var u = AppUser;

            if (IsSupperAdmin || u.ID == userInfo.ID)
            {
                userInfo.ID   = u.ID;
                userInfo.Name = u.Name;
                await _userService.UpdateAsync(userInfo.ToDictionary());
            }
            else
            {
                throw ApiException.Common(RequestLocalizer["No permission"]);
            }

            return(ApiResult.Ok(true));
        }
コード例 #18
0
        public async Task <ApiResult <JwtToken> > Login(RequestRegister model, [FromQuery] string culture)
        {
            IUser user;

            Microsoft.AspNetCore.Identity.SignInResult result;

            switch (model.Type)
            {
            case 1:
                user = await _userService.FindByPhoneNumberAsync(model.Mobile);

                result = await _userService.LoginAsync(user, model.Password);

                break;

            case 2:
                if (!CheckVerCode(model.InternationalAreaCode + model.Mobile, model.VerCode, 0))
                {
                    throw ApiException.Common(RequestLocalizer["The verification code is incorrect or expired"]);
                }
                user = await _userService.FindByPhoneNumberAsync(model.Mobile);

                result = await _userService.LoginAsync(user);

                break;

            case 3:
                user = await _userService.FindByEmailAsync(model.Mail);

                result = await _userService.LoginAsync(user, model.Password);

                break;

            case 4:
                if (!CheckVerCode(model.Mail, model.VerCode, 1))
                {
                    throw ApiException.Common(RequestLocalizer["The verification code is incorrect or expired"]);
                }
                user = await _userService.FindByEmailAsync(model.Mail);

                result = await _userService.LoginAsync(user);

                break;

            case 0:
            default:
                user = await _userService.FindByNameAsync(model.UserName);

                result = await _userService.LoginAsync(user, model.Password);

                break;
            }

            if (result.Succeeded)
            {
                var jwtToken = HttpContext.Features.Get <JwtToken>();
                return(ApiResult.Ok(jwtToken));
            }

            throw ApiException.Common(RequestLocalizer["Wrong account or password"]);
        }
コード例 #19
0
        /// <summary>
        /// 获取或创建用户
        /// </summary>
        /// <returns></returns>
        private async Task <IManageUser> GetOrCreateUserAsync(ClaimsPrincipal user, AuthenticationProperties properties)
        {
            var options  = Options;
            var provider = properties.Items["scheme"];
            var openid   = user.FindFirstValue(OAuthSignInAuthenticationDefaults.Sub);

            var uc = UserConnect.FindByProviderAndOpenID(provider, openid);

            IManageUser appUser;

            if (uc == null)
            {
                if (!options.CreateUserOnOAuthLogin)
                {
                    throw ApiException.Common("用户不存在,请联系管理员");
                }

                uc = new UserConnect()
                {
                    Provider = provider, OpenID = openid, Enable = true
                };
                uc.Fill(user);

                appUser = new ApplicationUser {
                    Name = Guid.NewGuid().ToString().Substring(0, 8), Enable = true, RoleID = 4
                };                                                                                                            // 角色id 4 为游客

                // 此处可改用本系统服务替换,去除ApplicationUser依赖
                var result = await _userManager.CreateAsync(appUser as ApplicationUser, "123456");

                if (!result.Succeeded)
                {
                    throw ApiException.Common($"创建用户失败:{result.Errors.First().Description}");
                }

                uc.UserID = appUser.ID;
            }
            else
            {
                appUser = await _userManager.FindByIdAsync(uc.UserID.ToString());
            }

            if (!appUser.Enable)
            {
                throw ApiException.Common($"用户已被禁用");
            }

            // 填充用户信息
            Fill(appUser, user);

            if (appUser is IAuthUser user3)
            {
                user3.Logins++;
                user3.LastLogin   = DateTime.Now;
                user3.LastLoginIP = Request.Host.Host;
                user3.Save();
            }

            try
            {
                uc.Save();
            }
            catch (Exception ex)
            {
                //为了防止某些特殊数据导致的无法正常登录,把所有异常记录到日志当中。忽略错误
                XTrace.WriteException(ex);
            }

            return(appUser);
        }
コード例 #20
0
        /// <summary>
        /// 获取或创建用户
        /// </summary>
        /// <returns></returns>
        public virtual async Task <IManageUser> GetOrCreateUserAsync(ClaimsPrincipal user, AuthenticationProperties properties, bool createUserOnOAuthLogin)
        {
            var provider = properties.Items["scheme"];
            var openid   = user.FindFirstValue(OAuthSignInAuthenticationDefaults.Sub);

            var uc = UserConnect.FindByProviderAndOpenID(provider, openid);

            IManageUser appUser;

            if (uc == null)
            {
                if (!createUserOnOAuthLogin)
                {
                    throw ApiException.Common(_requestLocalizer["The user does not exist, please contact the administrator"]);
                }

                uc = new UserConnect()
                {
                    Provider = provider, OpenID = openid, Enable = true
                };
                uc.Fill(user);

                appUser = new TUser
                {
                    Name   = Guid.NewGuid().ToString().Substring(0, 8),
                    Enable = true,
                    RoleID = 4
                }; // 角色id 4 为游客

                // 通过第三方登录创建的用户设置随机密码
                var result = await _userManager.CreateAsync((TUser)appUser, Guid.NewGuid().ToString().Substring(0, 8));

                if (!result.Succeeded)
                {
                    throw ApiException.Common($"{_requestLocalizer["Failed to create user"]}:{_requestLocalizer[result.Errors.First().Description]}");
                }

                uc.UserID = appUser.ID;
            }
            else
            {
                appUser = await _userManager.FindByIdAsync(uc.UserID.ToString()) as IManageUser;
            }

            if (appUser == null)
            {
                throw ApiException.Common(_requestLocalizer["The user was not found"]);
            }

            if (!appUser.Enable)
            {
                throw ApiException.Common(_requestLocalizer["The user has been disabled"]);
            }

            // 填充用户信息
            Fill(appUser, user);

            if (appUser is IAuthUser user3)
            {
                user3.Logins++;
                user3.LastLogin = DateTime.Now;
                //user3.LastLoginIP = Request.Host.Host;
                user3.Save();
            }

            try
            {
                uc.Save();
            }
            catch (Exception ex)
            {
                //为了防止某些特殊数据导致的无法正常登录,把所有异常记录到日志当中。忽略错误
                XTrace.WriteException(ex);
            }

            return(appUser);
        }
コード例 #21
0
        bool SetPrincipal(AuthorizationFilterContext actionContext)
        {
            var context          = actionContext.HttpContext;
            var requestLocalizer = context.RequestServices.GetRequiredService <IStringLocalizer <Request> >();

            var userService =
                (actionContext.HttpContext.RequestServices.GetRequiredService(typeof(IUserService)) as IUserService) ?? throw ApiException.Common(requestLocalizer["IUserService is not registered"], 500);

            if (!context.User.Identity.IsAuthenticated)
            {
                return(false);
            }

            var id = context.User.FindFirst(JwtRegisteredClaimNames.NameId)?.Value;

            if (id == null)
            {
                id = context.User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
            }

            if (id == null)
            {
                id = context.User.FindFirst(JwtRegisteredClaimNames.Sub)?.Value;
            }

            if (id == null)
            {
                XTrace.WriteLine("context.User中找不到存放id的声明");
                throw new ApiException(500, requestLocalizer["Could not find the id claim in context.User"]);
            }

            var user = userService.FindByIdAsync(id).Result;

            if (user == null)
            {
                return(false);
            }

            var ac = user;

            ////将搜索到的AccessToken映射到IIdentity,用户名,权限role
            var iid = (IIdentity)ac;

            // 角色列表
            var up = new GenericPrincipal(iid, new[] { iid.AuthenticationType });

            context.Features[typeof(IUser)] = iid as IUser;
            context.User = up;

            Thread.CurrentPrincipal = up;

            return(true);
        }
コード例 #22
0
        public async Task <ApiResult <string> > Register(RequestRegister model, [FromQuery] string culture)
        {
            string[] names;
            object[] values;

            switch (model.Type)
            {
            case 1:
            case 2:
                if (!CheckVerCode(model.InternationalAreaCode + model.Mobile, model.VerCode, 0))
                {
                    throw ApiException.Common(RequestLocalizer["The verification code is incorrect or expired"]);
                }
                names = new[]
                {
                    nameof(IUser.Name),
                    nameof(IUser.DisplayName),
                    nameof(IUser.Mobile),
                    nameof(IUser.Password),
                };
                // 模式2,不带密码,默认密码由内部生成,应用应该引导用户修改密码后使用
                values = new object[] { model.Mobile, model.Mobile, model.Mobile, model.Password };
                break;

            case 3:
            case 4:
                if (!CheckVerCode(model.Mail, model.VerCode, 1))
                {
                    throw ApiException.Common(RequestLocalizer["The verification code is incorrect or expired"]);
                }
                names = new[]
                {
                    nameof(IUser.Name),
                    nameof(IUser.DisplayName),
                    nameof(IUser.Mail),
                    nameof(IUser.Password),
                };
                values = new object[] { model.Mail, model.Mail, model.Mail, model.Password };
                break;

            case 0:
            default:
                names = new[]
                {
                    nameof(IUser.Name),
                    nameof(IUser.DisplayName),
                    nameof(IUser.Password),
                };
                values = new object[] { model.UserName, model.UserName, model.Password };
                break;
            }

            var result = await _userService.CreateAsync(names, values);

            if (result.Succeeded)
            {
                return(ApiResult.Ok());
            }

            var err = result.Errors.ToArray()[0];

            XTrace.WriteLine($"创建用户发生错误:{err.Description}");

            throw ApiException.Common(RequestLocalizer[err.Code]);
        }