feat: add steam support (#497)

* feat: add steam support

Signed-off-by: 0x2a <stevesough@gmail.com>

* fix: wrong name

Signed-off-by: Steve0x2a <stevesough@gmail.com>
This commit is contained in:
Steve0x2a
2022-02-16 19:57:46 +08:00
committed by GitHub
parent 4122c94205
commit 661abd6b6e
9 changed files with 76 additions and 9 deletions

View File

@ -109,7 +109,7 @@ func (c *ApiController) GetApplicationLogin() {
} }
func setHttpClient(idProvider idp.IdProvider, providerType string) { func setHttpClient(idProvider idp.IdProvider, providerType string) {
if providerType == "GitHub" || providerType == "Google" || providerType == "Facebook" || providerType == "LinkedIn" { if providerType == "GitHub" || providerType == "Google" || providerType == "Facebook" || providerType == "LinkedIn" || providerType == "Steam" {
idProvider.SetHttpClient(proxy.ProxyHttpClient) idProvider.SetHttpClient(proxy.ProxyHttpClient)
} else { } else {
idProvider.SetHttpClient(proxy.DefaultHttpClient) idProvider.SetHttpClient(proxy.DefaultHttpClient)

View File

@ -45,6 +45,7 @@ import (
"github.com/markbates/goth/providers/salesforce" "github.com/markbates/goth/providers/salesforce"
"github.com/markbates/goth/providers/shopify" "github.com/markbates/goth/providers/shopify"
"github.com/markbates/goth/providers/slack" "github.com/markbates/goth/providers/slack"
"github.com/markbates/goth/providers/steam"
"github.com/markbates/goth/providers/tumblr" "github.com/markbates/goth/providers/tumblr"
"github.com/markbates/goth/providers/twitter" "github.com/markbates/goth/providers/twitter"
"github.com/markbates/goth/providers/yahoo" "github.com/markbates/goth/providers/yahoo"
@ -171,6 +172,11 @@ func NewGothIdProvider(providerType string, clientId string, clientSecret string
Provider: slack.New(clientId, clientSecret, redirectUrl), Provider: slack.New(clientId, clientSecret, redirectUrl),
Session: &slack.Session{}, Session: &slack.Session{},
} }
case "Steam":
idp = GothIdProvider{
Provider: steam.New(clientSecret, redirectUrl),
Session: &steam.Session{},
}
case "Tumblr": case "Tumblr":
idp = GothIdProvider{ idp = GothIdProvider{
Provider: tumblr.New(clientId, clientSecret, redirectUrl), Provider: tumblr.New(clientId, clientSecret, redirectUrl),
@ -209,10 +215,21 @@ func (idp *GothIdProvider) SetHttpClient(client *http.Client) {
func (idp *GothIdProvider) GetToken(code string) (*oauth2.Token, error) { func (idp *GothIdProvider) GetToken(code string) (*oauth2.Token, error) {
var expireAt time.Time var expireAt time.Time
//Need to construct variables supported by goth var value url.Values
//to call the function to obtain accessToken var err error
value := url.Values{} if idp.Provider.Name() == "steam" {
value.Add("code", code) value, err = url.ParseQuery(code)
returnUrl := reflect.ValueOf(idp.Session).Elem().FieldByName("CallbackURL")
returnUrl.Set(reflect.ValueOf(value.Get("openid.return_to")))
if err != nil {
return nil, err
}
} else {
//Need to construct variables supported by goth
//to call the function to obtain accessToken
value = url.Values{}
value.Add("code", code)
}
accessToken, err := idp.Session.Authorize(idp.Provider, value) accessToken, err := idp.Session.Authorize(idp.Provider, value)
//Get ExpiresAt's value //Get ExpiresAt's value
valueOfExpire := reflect.ValueOf(idp.Session).Elem().FieldByName("ExpiresAt") valueOfExpire := reflect.ValueOf(idp.Session).Elem().FieldByName("ExpiresAt")
@ -231,10 +248,10 @@ func (idp *GothIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
return getUser(gothUser), nil return getUser(gothUser, idp.Provider.Name()), nil
} }
func getUser(gothUser goth.User) *UserInfo { func getUser(gothUser goth.User, provider string) *UserInfo {
user := UserInfo{ user := UserInfo{
Id: gothUser.UserID, Id: gothUser.UserID,
Username: gothUser.Name, Username: gothUser.Name,
@ -258,7 +275,10 @@ func getUser(gothUser goth.User) *UserInfo {
user.DisplayName = user.Username user.DisplayName = user.Username
} }
} }
if provider == "steam" {
user.Username = user.DisplayName
user.Email = ""
}
return &user return &user
} }

View File

@ -83,7 +83,7 @@ func GetIdProvider(typ string, subType string, clientId string, clientSecret str
return nil return nil
} }
var gothList = []string{"Apple", "AzureAd", "Slack"} var gothList = []string{"Apple", "AzureAd", "Slack", "Steam"}
func isGothSupport(provider string) bool { func isGothSupport(provider string) bool {
for _, value := range gothList { for _, value := range gothList {

View File

@ -84,6 +84,7 @@ type User struct {
Apple string `xorm:"apple varchar(100)" json:"apple"` Apple string `xorm:"apple varchar(100)" json:"apple"`
AzureAD string `xorm:"azuread varchar(100)" json:"azuread"` AzureAD string `xorm:"azuread varchar(100)" json:"azuread"`
Slack string `xorm:"slack varchar(100)" json:"slack"` Slack string `xorm:"slack varchar(100)" json:"slack"`
Steam string `xorm:"steam varchar(100)" json:"steam"`
Ldap string `xorm:"ldap varchar(100)" json:"ldap"` Ldap string `xorm:"ldap varchar(100)" json:"ldap"`
Properties map[string]string `json:"properties"` Properties map[string]string `json:"properties"`

View File

@ -403,6 +403,7 @@ export function getProviderTypeOptions(category) {
{id: 'Apple', name: 'Apple'}, {id: 'Apple', name: 'Apple'},
{id: 'AzureAD', name: 'AzureAD'}, {id: 'AzureAD', name: 'AzureAD'},
{id: 'Slack', name: 'Slack'}, {id: 'Slack', name: 'Slack'},
{id: 'Steam', name: 'Steam'},
] ]
); );
} else if (category === "Email") { } else if (category === "Email") {

View File

@ -69,6 +69,7 @@ class AuthCallback extends React.Component {
UNSAFE_componentWillMount() { UNSAFE_componentWillMount() {
const params = new URLSearchParams(this.props.location.search); const params = new URLSearchParams(this.props.location.search);
let isSteam = params.get("openid.mode")
let code = params.get("code"); let code = params.get("code");
// WeCom returns "auth_code=xxx" instead of "code=xxx" // WeCom returns "auth_code=xxx" instead of "code=xxx"
if (code === null) { if (code === null) {
@ -78,6 +79,10 @@ class AuthCallback extends React.Component {
if (code === null) { if (code === null) {
code = params.get("authCode") code = params.get("authCode")
} }
//Steam don't use code, so we should use all params as code.
if (isSteam !== null && code === null) {
code = this.props.location.search
}
const innerParams = this.getInnerParams(); const innerParams = this.getInnerParams();
const applicationName = innerParams.get("application"); const applicationName = innerParams.get("application");

View File

@ -39,6 +39,7 @@ import InfoflowLoginButton from "./InfoflowLoginButton";
import AppleLoginButton from "./AppleLoginButton" import AppleLoginButton from "./AppleLoginButton"
import AzureADLoginButton from "./AzureADLoginButton"; import AzureADLoginButton from "./AzureADLoginButton";
import SlackLoginButton from "./SlackLoginButton"; import SlackLoginButton from "./SlackLoginButton";
import SteamLoginButton from "./SteamLoginButton";
import CustomGithubCorner from "../CustomGithubCorner"; import CustomGithubCorner from "../CustomGithubCorner";
import {CountDownInput} from "../common/CountDownInput"; import {CountDownInput} from "../common/CountDownInput";
@ -197,6 +198,8 @@ class LoginPage extends React.Component {
return <AzureADLoginButton text={text} align={"center"} /> return <AzureADLoginButton text={text} align={"center"} />
} else if (type === "Slack") { } else if (type === "Slack") {
return <SlackLoginButton text={text} align={"center"} /> return <SlackLoginButton text={text} align={"center"} />
} else if (type === "Steam") {
return <SteamLoginButton text={text} align={"center"} />
} }
return text; return text;

View File

@ -89,6 +89,9 @@ const authInfo = {
scope: "users:read", scope: "users:read",
endpoint: "https://slack.com/oauth/authorize", endpoint: "https://slack.com/oauth/authorize",
}, },
Steam: {
endpoint: "https://steamcommunity.com/openid/login",
},
}; };
const otherProviderInfo = { const otherProviderInfo = {
@ -274,5 +277,7 @@ export function getAuthUrl(application, provider, method) {
return `${endpoint}?client_id=${provider.clientId}&redirect_uri=${redirectUri}&state=${state}&response_type=code&scope=${scope}&resource=https://graph.windows.net/`; return `${endpoint}?client_id=${provider.clientId}&redirect_uri=${redirectUri}&state=${state}&response_type=code&scope=${scope}&resource=https://graph.windows.net/`;
} else if (provider.type === "Slack") { } else if (provider.type === "Slack") {
return `${endpoint}?client_id=${provider.clientId}&redirect_uri=${redirectUri}&state=${state}&response_type=code&scope=${scope}`; return `${endpoint}?client_id=${provider.clientId}&redirect_uri=${redirectUri}&state=${state}&response_type=code&scope=${scope}`;
} else if (provider.type === "Steam") {
return `${endpoint}?openid.claimed_id=http://specs.openid.net/auth/2.0/identifier_select&openid.identity=http://specs.openid.net/auth/2.0/identifier_select&openid.mode=checkid_setup&openid.ns=http://specs.openid.net/auth/2.0&openid.realm=${window.location.origin}&openid.return_to=${redirectUri}?state=${state}`;
} }
} }

View File

@ -0,0 +1,32 @@
// Copyright 2022 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import {createButton} from "react-social-login-buttons";
import {StaticBaseUrl} from "../Setting";
function Icon({ width = 24, height = 24, color }) {
return <img src={`${StaticBaseUrl}/buttons/steam.svg`} alt="Sign in with Steam" style={{width: 24, height: 24}} />;
}
const config = {
text: "Sign in with Steam",
icon: Icon,
iconFormat: name => `fa fa-${name}`,
style: {background: "#ffffff", color: "#000000"},
activeStyle: {background: "#ededee"},
};
const SteamLoginButton = createButton(config);
export default SteamLoginButton;