common oidc
Signed-off-by: dignow <linlong1265@gmail.com>
1
flutter/assets/auth-apple.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg enable-background="new 0 0 1024 1024" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg"><circle cx="512" cy="512" fill="#999" r="512"/><path d="m407.2 722.1c-10.1-6.7-19-15-26.5-24.5-8.2-9.9-15.7-20.3-22.7-31-16.3-23.9-29.1-50-38-77.5-10.7-32-15.8-62.7-15.8-92.7 0-33.5 7.2-62.7 21.4-87.2 10.4-19.2 26-35.2 44.8-46.5 18.1-11.3 39.2-17.5 60.6-17.9 7.5 0 15.6 1.1 24.1 3.2 6.2 1.7 13.6 4.5 22.8 7.9 11.7 4.5 18.1 7.2 20.3 7.9 6.8 2.6 12.6 3.6 17.1 3.6 3.4 0 8.3-1.1 13.8-2.8 3.1-1.1 9-3 17.3-6.6 8.2-3 14.8-5.5 19.9-7.5 7.9-2.3 15.5-4.5 22.4-5.5 8.3-1.3 16.6-1.7 24.5-1.1 15.1 1.1 29 4.3 41.4 9 21.7 8.7 39.3 22.4 52.4 41.8-5.5 3.4-10.7 7.4-15.5 11.7-10.4 9.2-19.2 20-26.2 32.1-9.2 16.4-13.9 35-13.7 53.7.3 23.1 6.2 43.4 17.9 61 8.3 12.8 19.3 23.8 32.7 32.7 6.6 4.5 12.4 7.6 17.9 9.6-2.6 8-5.4 15.8-8.6 23.5-7.4 17.2-16.2 33.7-26.7 49.3-9.2 13.4-16.5 23.5-22 30.1-8.6 10.2-16.8 17.9-25.2 23.4-9.2 6.1-19.9 9.3-31 9.3-7.5.3-14.9-.6-22-2.7-6.2-2-12.3-4.3-18.3-6.9-6.2-2.9-12.7-5.3-19.3-7.2-8.1-2.1-16.4-3.2-24.8-3.1-8.5 0-16.8 1.1-24.7 3.1-6.6 1.9-13 4.2-19.3 6.9-9 3.7-14.8 6.2-18.2 7.2-6.9 2-14 3.3-21.1 3.7-11.1 0-21.4-3.2-31.7-9.6zm146.1-393.6c-14.5 7.2-28.3 10.3-42.1 9.3-2.1-13.8 0-27.9 5.8-43.4 5.1-13.2 11.9-25.2 21.3-35.8 9.8-11.1 21.5-20.3 34.8-26.9 14.1-7.2 27.5-11.1 40.3-11.7 1.7 14.5 0 28.8-5.3 44.1-4.9 13.6-12.1 26.2-21.3 37.5-9.3 11.1-20.8 20.3-33.8 26.9z" fill="#fff"/></svg>
|
After Width: | Height: | Size: 1.4 KiB |
1
flutter/assets/auth-azure.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg height="199" viewBox="0 0 256 199" width="256" xmlns="http://www.w3.org/2000/svg"><path d="m118.431947 187.698037c32.890056-5.8101 60.055363-10.617957 60.367362-10.684121l.567276-.120304-31.051455-36.934731c-17.078287-20.314105-31.05144-37.0135-31.05144-37.109763 0-.182257 32.06325-88.4775168 32.243499-88.791861.060266-.104805 21.880281 37.566853 52.893149 91.318807 29.034814 50.323542 52.972611 91.815483 53.195106 92.204295l.404552.706942-98.684084-.012729-98.6840664-.012677 59.8001014-10.563822zm-118.43195104-11.263314c0-.052002 14.63129504-25.450782 32.51398844-56.441754l32.5139832-56.3472172 37.8912894-31.7984466c20.840208-17.4891418 37.94741-31.81982192 38.015996-31.84667602.068586-.02541214-.205562.66458386-.609219 1.53405261-.403657.86946874-18.91873 40.58235031-41.1446072 88.25084461l-40.4106754 86.6699876-29.3853777.036841c-16.1619541.020284-29.38537774-.005691-29.38537774-.057652z" fill="#0089d6"/></svg>
|
After Width: | Height: | Size: 932 B |
14
flutter/assets/auth-default.svg
Normal file
@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="200px" height="200px" style="shape-rendering:geometricPrecision; text-rendering:geometricPrecision; image-rendering:optimizeQuality; fill-rule:evenodd; clip-rule:evenodd" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<g><path style="opacity:0.992" fill="#93d2f7" d="M 86.5,8.5 C 124.806,5.40814 154.973,19.4081 177,50.5C 192.266,77.4137 194.6,105.414 184,134.5C 170.11,165.714 146.277,184.214 112.5,190C 64.6272,193.661 31.4605,173.494 13,129.5C 0.908201,86.4442 12.4082,51.2776 47.5,24C 59.6417,16.3486 72.6417,11.182 86.5,8.5 Z"/></g>
|
||||
<g><path style="opacity:1" fill="#b5a6a0" d="M 132.5,79.5 C 131.5,79.5 130.5,79.5 129.5,79.5C 129.5,91.8333 129.5,104.167 129.5,116.5C 128.505,104.011 128.171,91.3443 128.5,78.5C 130.099,78.2322 131.432,78.5655 132.5,79.5 Z"/></g>
|
||||
<g><path style="opacity:1" fill="#e85d18" d="M 113.5,80.5 C 114.5,80.5 115.5,80.5 116.5,80.5C 116.5,83.5 116.5,86.5 116.5,89.5C 118.5,89.5 120.5,89.5 122.5,89.5C 122.5,90.5 122.5,91.5 122.5,92.5C 120.5,92.5 118.5,92.5 116.5,92.5C 116.334,99.175 116.5,105.842 117,112.5C 119.473,113.12 121.973,113.786 124.5,114.5C 124.291,115.086 123.957,115.586 123.5,116C 120.007,117.004 116.841,116.504 114,114.5C 113.5,107.174 113.334,99.8409 113.5,92.5C 112.167,92.5 110.833,92.5 109.5,92.5C 109.5,91.5 109.5,90.5 109.5,89.5C 110.833,89.5 112.167,89.5 113.5,89.5C 113.5,86.5 113.5,83.5 113.5,80.5 Z"/></g>
|
||||
<g><path style="opacity:1" fill="#cc9d86" d="M 84.5,90.5 C 83.5,90.5 82.5,90.5 81.5,90.5C 81.5,96.1667 81.5,101.833 81.5,107.5C 80.5104,101.69 80.1771,95.69 80.5,89.5C 82.099,89.2322 83.4324,89.5655 84.5,90.5 Z"/></g>
|
||||
<g><path style="opacity:1" fill="#ed7d43" d="M 84.5,90.5 C 84.0753,97.6154 84.5753,104.615 86,111.5C 88.6362,114.947 91.8029,115.447 95.5,113C 96.7051,111.624 98.0384,110.458 99.5,109.5C 99.5,110.167 99.5,110.833 99.5,111.5C 95.1388,117.925 89.8055,118.925 83.5,114.5C 82.0562,112.392 81.3896,110.059 81.5,107.5C 81.5,101.833 81.5,96.1667 81.5,90.5C 82.5,90.5 83.5,90.5 84.5,90.5 Z"/></g>
|
||||
<g><path style="opacity:1" fill="#e75a15" d="M 100.5,90.5 C 101.5,90.5 102.5,90.5 103.5,90.5C 103.175,98.0191 103.508,105.352 104.5,112.5C 105.234,113.708 105.567,115.041 105.5,116.5C 104.022,116.762 102.689,116.429 101.5,115.5C 101.006,113.974 100.339,112.641 99.5,111.5C 99.5,110.833 99.5,110.167 99.5,109.5C 100.418,103.225 100.751,96.8918 100.5,90.5 Z"/></g>
|
||||
<g><path style="opacity:1" fill="#b6a198" d="M 100.5,90.5 C 101.568,89.5655 102.901,89.2322 104.5,89.5C 104.5,97.1667 104.5,104.833 104.5,112.5C 103.508,105.352 103.175,98.0191 103.5,90.5C 102.5,90.5 101.5,90.5 100.5,90.5 Z"/></g>
|
||||
<g><path style="opacity:1" fill="#ed8750" d="M 58.5,80.5 C 59.9778,80.238 61.3112,80.5713 62.5,81.5C 67.5678,93.0431 72.2345,104.71 76.5,116.5C 75.1779,116.67 74.0113,116.337 73,115.5C 71.8824,112.145 70.3824,108.978 68.5,106C 62.8431,105.501 57.1764,105.334 51.5,105.5C 50.3812,108.843 49.0479,112.177 47.5,115.5C 46.675,116.386 45.675,116.719 44.5,116.5C 48.7066,104.303 53.3732,92.303 58.5,80.5 Z"/></g>
|
||||
<g><path style="opacity:1" fill="#98cff0" d="M 59.5,85.5 C 60.4972,85.4701 61.1639,85.9701 61.5,87C 63.5976,91.7929 65.5976,96.6262 67.5,101.5C 62.8804,102.493 58.2137,102.827 53.5,102.5C 55.1125,96.6607 57.1125,90.994 59.5,85.5 Z"/></g>
|
||||
<g><path style="opacity:1" fill="#eb631b" d="M 132.5,79.5 C 132.334,84.8437 132.501,90.1771 133,95.5C 137.748,88.9184 143.414,87.9184 150,92.5C 151.401,100.415 151.901,108.415 151.5,116.5C 150.5,116.5 149.5,116.5 148.5,116.5C 148.666,110.158 148.5,103.825 148,97.5C 145.852,92.4656 142.352,91.2989 137.5,94C 135.622,95.5429 134.122,97.3762 133,99.5C 132.501,105.157 132.334,110.824 132.5,116.5C 131.5,116.5 130.5,116.5 129.5,116.5C 129.5,104.167 129.5,91.8333 129.5,79.5C 130.5,79.5 131.5,79.5 132.5,79.5 Z"/></g>
|
||||
</svg>
|
After Width: | Height: | Size: 3.8 KiB |
1
flutter/assets/auth-facebook.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"><rect fill="#1877f2" height="512" rx="76.8" width="512"/><path d="m355.6 330 11.4-74h-71v-48c0-20.2 9.9-40 41.7-40h32.3v-63s-29.3-5-57.3-5c-58.5 0-96.7 35.4-96.7 99.6v56.4h-65v74h65v182h80v-182z" fill="#fff"/></svg>
|
After Width: | Height: | Size: 277 B |
Before Width: | Height: | Size: 792 B After Width: | Height: | Size: 792 B |
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
@ -2314,3 +2314,10 @@ Widget unreadTopRightBuilder(RxInt? count, {Widget? icon}) {
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
String toCapitalized(String s) {
|
||||
if (s.isEmpty) {
|
||||
return s;
|
||||
}
|
||||
return s.substring(0, 1).toUpperCase() + s.substring(1);
|
||||
}
|
||||
|
@ -13,13 +13,13 @@ import '../../common.dart';
|
||||
import './dialog.dart';
|
||||
|
||||
class _IconOP extends StatelessWidget {
|
||||
final String icon;
|
||||
final double iconWidth;
|
||||
final String op;
|
||||
final String? icon;
|
||||
final EdgeInsets margin;
|
||||
const _IconOP(
|
||||
{Key? key,
|
||||
required this.op,
|
||||
required this.icon,
|
||||
required this.iconWidth,
|
||||
this.margin = const EdgeInsets.symmetric(horizontal: 4.0)})
|
||||
: super(key: key);
|
||||
|
||||
@ -27,10 +27,15 @@ class _IconOP extends StatelessWidget {
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
margin: margin,
|
||||
child: SvgPicture.asset(
|
||||
'assets/$icon.svg',
|
||||
width: iconWidth,
|
||||
),
|
||||
child: icon == null
|
||||
? SvgPicture.asset(
|
||||
'assets/auth-${op.toLowerCase()}.svg',
|
||||
width: 20,
|
||||
)
|
||||
: SvgPicture.string(
|
||||
icon!,
|
||||
width: 20,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -38,7 +43,7 @@ class _IconOP extends StatelessWidget {
|
||||
class ButtonOP extends StatelessWidget {
|
||||
final String op;
|
||||
final RxString curOP;
|
||||
final double iconWidth;
|
||||
final String? icon;
|
||||
final Color primaryColor;
|
||||
final double height;
|
||||
final Function() onTap;
|
||||
@ -47,7 +52,7 @@ class ButtonOP extends StatelessWidget {
|
||||
Key? key,
|
||||
required this.op,
|
||||
required this.curOP,
|
||||
required this.iconWidth,
|
||||
required this.icon,
|
||||
required this.primaryColor,
|
||||
required this.height,
|
||||
required this.onTap,
|
||||
@ -71,15 +76,15 @@ class ButtonOP extends StatelessWidget {
|
||||
SizedBox(
|
||||
width: 30,
|
||||
child: _IconOP(
|
||||
icon: op,
|
||||
iconWidth: iconWidth,
|
||||
op: op,
|
||||
icon: icon,
|
||||
margin: EdgeInsets.only(right: 5),
|
||||
)),
|
||||
Expanded(
|
||||
child: FittedBox(
|
||||
fit: BoxFit.scaleDown,
|
||||
child: Center(
|
||||
child: Text('${translate("Continue with")} $op')))),
|
||||
child: Text('${translate("Continue with")} ${toCapitalized(op)}')))),
|
||||
],
|
||||
))),
|
||||
),
|
||||
@ -89,8 +94,8 @@ class ButtonOP extends StatelessWidget {
|
||||
|
||||
class ConfigOP {
|
||||
final String op;
|
||||
final double iconWidth;
|
||||
ConfigOP({required this.op, required this.iconWidth});
|
||||
final String? icon;
|
||||
ConfigOP({required this.op, required this.icon});
|
||||
}
|
||||
|
||||
class WidgetOP extends StatefulWidget {
|
||||
@ -182,7 +187,7 @@ class _WidgetOPState extends State<WidgetOP> {
|
||||
ButtonOP(
|
||||
op: widget.config.op,
|
||||
curOP: widget.curOP,
|
||||
iconWidth: widget.config.iconWidth,
|
||||
icon: widget.config.icon,
|
||||
primaryColor: str2color(widget.config.op, 0x7f),
|
||||
height: 36,
|
||||
onTap: () async {
|
||||
@ -380,7 +385,7 @@ Future<bool?> loginDialog() async {
|
||||
|
||||
final loginOptions = [].obs;
|
||||
Future.delayed(Duration.zero, () async {
|
||||
loginOptions.value = await UserModel.queryLoginOptions();
|
||||
loginOptions.value = await UserModel.queryOidcLoginOptions();
|
||||
});
|
||||
|
||||
final res = await gFFI.dialogManager.show<bool>((setState, close, context) {
|
||||
@ -460,12 +465,8 @@ Future<bool?> loginDialog() async {
|
||||
}
|
||||
|
||||
thirdAuthWidget() => Obx(() {
|
||||
final oidcOptions = loginOptions
|
||||
.where((opt) => opt.startsWith(kAuthReqTypeOidc))
|
||||
.map((opt) => opt.substring(kAuthReqTypeOidc.length))
|
||||
.toList();
|
||||
return Offstage(
|
||||
offstage: oidcOptions.isEmpty,
|
||||
offstage: loginOptions.isEmpty,
|
||||
child: Column(
|
||||
children: [
|
||||
const SizedBox(
|
||||
@ -480,12 +481,8 @@ Future<bool?> loginDialog() async {
|
||||
height: 8.0,
|
||||
),
|
||||
LoginWidgetOP(
|
||||
ops: [
|
||||
ConfigOP(op: 'GitHub', iconWidth: 20),
|
||||
ConfigOP(op: 'Google', iconWidth: 20),
|
||||
ConfigOP(op: 'Okta', iconWidth: 38),
|
||||
]
|
||||
.where((op) => oidcOptions.contains(op.op.toLowerCase()))
|
||||
ops: loginOptions
|
||||
.map((e) => ConfigOP(op: e['name'], icon: e['icon']))
|
||||
.toList(),
|
||||
curOP: curOP,
|
||||
cbLogin: (Map<String, dynamic> authBody) {
|
||||
|
@ -163,15 +163,15 @@ class UserModel {
|
||||
return loginResponse;
|
||||
}
|
||||
|
||||
static Future<List<dynamic>> queryLoginOptions() async {
|
||||
static Future<List<dynamic>> queryOidcLoginOptions() async {
|
||||
try {
|
||||
final url = await bind.mainGetApiServer();
|
||||
if (url.trim().isEmpty) return [];
|
||||
final resp = await http.get(Uri.parse('$url/api/login-options'));
|
||||
final resp = await http.get(Uri.parse('$url/api/oidc/login-options'));
|
||||
return jsonDecode(resp.body);
|
||||
} catch (e) {
|
||||
debugPrint(
|
||||
"queryLoginOptions: jsonDecode resp body failed: ${e.toString()}");
|
||||
"queryOidcLoginOptions: jsonDecode resp body failed: ${e.toString()}");
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|