Social SignOn

This commit is contained in:
MaxKey 2022-05-16 11:11:17 +08:00
parent 36ea37aff2
commit 63f33facac
10 changed files with 80 additions and 64 deletions

View File

@ -64,13 +64,13 @@ public class AbstractSocialSignOnEndpoint {
@Autowired @Autowired
ApplicationConfig applicationConfig; ApplicationConfig applicationConfig;
protected AuthRequest buildAuthRequest(String instId,String provider){ protected AuthRequest buildAuthRequest(String instId,String provider,String baseUrl){
try { try {
SocialsProvider socialSignOnProvider = socialSignOnProviderService.get(instId,provider); SocialsProvider socialSignOnProvider = socialSignOnProviderService.get(instId,provider);
_logger.debug("socialSignOn Provider : "+socialSignOnProvider); _logger.debug("socialSignOn Provider : "+socialSignOnProvider);
if(socialSignOnProvider != null){ if(socialSignOnProvider != null){
authRequest = socialSignOnProviderService.getAuthRequest(instId,provider,WebContext.getBaseUri()); authRequest = socialSignOnProviderService.getAuthRequest(instId,provider,baseUrl);
return authRequest; return authRequest;
} }
}catch(Exception e) { }catch(Exception e) {
@ -79,7 +79,7 @@ public class AbstractSocialSignOnEndpoint {
return null; return null;
} }
protected SocialsAssociate authCallback(String instId,String provider) throws Exception { protected SocialsAssociate authCallback(String instId,String provider,String baseUrl) throws Exception {
SocialsAssociate socialsAssociate = null; SocialsAssociate socialsAssociate = null;
AuthCallback authCallback=new AuthCallback(); AuthCallback authCallback=new AuthCallback();
authCallback.setCode(WebContext.getRequest().getParameter("code")); authCallback.setCode(WebContext.getRequest().getParameter("code"));
@ -97,7 +97,7 @@ public class AbstractSocialSignOnEndpoint {
authCallback.getState()); authCallback.getState());
if(authRequest == null) {//if authRequest is null renew one if(authRequest == null) {//if authRequest is null renew one
authRequest=socialSignOnProviderService.getAuthRequest(instId,provider,WebContext.getBaseUri()); authRequest=socialSignOnProviderService.getAuthRequest(instId,provider,baseUrl);
_logger.debug("session authRequest is null , renew one"); _logger.debug("session authRequest is null , renew one");
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright [2020] [MaxKey of copyright http://www.maxkey.top] * Copyright [2022] [MaxKey of copyright http://www.maxkey.top]
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -25,7 +25,6 @@ import javax.servlet.http.HttpServletRequest;
import org.maxkey.authn.LoginCredential; import org.maxkey.authn.LoginCredential;
import org.maxkey.authn.annotation.CurrentUser; import org.maxkey.authn.annotation.CurrentUser;
import org.maxkey.authn.jwt.AuthJwt; import org.maxkey.authn.jwt.AuthJwt;
import org.maxkey.authn.web.AuthorizationUtils;
import org.maxkey.constants.ConstsLoginType; import org.maxkey.constants.ConstsLoginType;
import org.maxkey.entity.Message; import org.maxkey.entity.Message;
import org.maxkey.entity.SocialsAssociate; import org.maxkey.entity.SocialsAssociate;
@ -38,6 +37,7 @@ import org.springframework.http.ResponseEntity;
import org.springframework.security.core.Authentication; import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Controller; import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.ResponseBody;
@ -54,23 +54,34 @@ public class SocialSignOnEndpoint extends AbstractSocialSignOnEndpoint{
@RequestMapping(value={"/authorize/{provider}"}, method = RequestMethod.GET) @RequestMapping(value={"/authorize/{provider}"}, method = RequestMethod.GET)
@ResponseBody @ResponseBody
public ResponseEntity<?> authorize(HttpServletRequest request, public ResponseEntity<?> authorize( HttpServletRequest request,
@PathVariable String provider @PathVariable String provider,
@RequestHeader("Origin") String originURL
) { ) {
_logger.trace("SocialSignOn provider : " + provider); _logger.trace("SocialSignOn provider : " + provider);
String instId = WebContext.getInst().getId(); String instId = WebContext.getInst().getId();
String authorizationUrl = buildAuthRequest(instId,provider).authorize(authTokenService.genRandomJwt()); String authorizationUrl =
buildAuthRequest(
instId,
provider,
originURL + applicationConfig.getFrontendUri()
).authorize(authTokenService.genRandomJwt());
_logger.trace("authorize SocialSignOn : " + authorizationUrl); _logger.trace("authorize SocialSignOn : " + authorizationUrl);
return new Message<Object>((Object)authorizationUrl).buildResponse(); return new Message<Object>((Object)authorizationUrl).buildResponse();
} }
@RequestMapping(value={"/scanqrcode/{provider}"}, method = RequestMethod.GET) @RequestMapping(value={"/scanqrcode/{provider}"}, method = RequestMethod.GET)
@ResponseBody @ResponseBody
public ResponseEntity<?> scanQRCode( public ResponseEntity<?> scanQRCode(HttpServletRequest request,
HttpServletRequest request, @PathVariable("provider") String provider,
@PathVariable("provider") String provider) { @RequestHeader("Origin") String originURL) {
String instId = WebContext.getInst().getId(); String instId = WebContext.getInst().getId();
AuthRequest authRequest = buildAuthRequest(instId,provider); AuthRequest authRequest =
buildAuthRequest(
instId,
provider,
originURL + applicationConfig.getFrontendUri());
if(authRequest == null ) { if(authRequest == null ) {
_logger.error("build authRequest fail ."); _logger.error("build authRequest fail .");
@ -82,17 +93,21 @@ public class SocialSignOnEndpoint extends AbstractSocialSignOnEndpoint{
SocialsProvider scanQrProvider = new SocialsProvider(socialSignOnProvider); SocialsProvider scanQrProvider = new SocialsProvider(socialSignOnProvider);
scanQrProvider.setState(state); scanQrProvider.setState(state);
scanQrProvider.setRedirectUri( scanQrProvider.setRedirectUri(
socialSignOnProviderService.getRedirectUri(WebContext.getBaseUri(), provider)); socialSignOnProviderService.getRedirectUri(
originURL + applicationConfig.getFrontendUri(), provider));
return new Message<SocialsProvider>(scanQrProvider).buildResponse(); return new Message<SocialsProvider>(scanQrProvider).buildResponse();
} }
@RequestMapping(value={"/bind/{provider}"}, method = RequestMethod.GET) @RequestMapping(value={"/bind/{provider}"}, method = RequestMethod.GET)
public ResponseEntity<?> bind(@PathVariable String provider,@CurrentUser UserInfo userInfo) { public ResponseEntity<?> bind(@PathVariable String provider,
@RequestHeader("Origin") String originURL,
@CurrentUser UserInfo userInfo) {
//auth call back may exception //auth call back may exception
try { try {
SocialsAssociate socialsAssociate = this.authCallback(userInfo.getInstId(),provider); SocialsAssociate socialsAssociate =
this.authCallback(userInfo.getInstId(),provider,originURL + applicationConfig.getFrontendUri());
socialsAssociate.setSocialUserInfo(accountJsonString); socialsAssociate.setSocialUserInfo(accountJsonString);
socialsAssociate.setUserId(userInfo.getId()); socialsAssociate.setUserId(userInfo.getId());
socialsAssociate.setUsername(userInfo.getUsername()); socialsAssociate.setUsername(userInfo.getUsername());
@ -111,11 +126,13 @@ public class SocialSignOnEndpoint extends AbstractSocialSignOnEndpoint{
} }
@RequestMapping(value={"/callback/{provider}"}, method = RequestMethod.GET) @RequestMapping(value={"/callback/{provider}"}, method = RequestMethod.GET)
public ResponseEntity<?> callback(@PathVariable String provider) { public ResponseEntity<?> callback(@PathVariable String provider,
@RequestHeader("Origin") String originURL) {
//auth call back may exception //auth call back may exception
try { try {
String instId = WebContext.getInst().getId(); String instId = WebContext.getInst().getId();
SocialsAssociate socialsAssociate = this.authCallback(instId,provider); SocialsAssociate socialsAssociate =
this.authCallback(instId,provider,originURL + applicationConfig.getFrontendUri());
socialsAssociate=this.socialsAssociateService.get(socialsAssociate); socialsAssociate=this.socialsAssociateService.get(socialsAssociate);

View File

@ -2,7 +2,7 @@
"name": "maxkey", "name": "maxkey",
"version": "3.5.0", "version": "3.5.0",
"description": "Leading-Edge IAM Identity and Access Management", "description": "Leading-Edge IAM Identity and Access Management",
"author": "MaxKey <maxkeysupport@163.com>", "author": "MaxKey <support@maxsso.net>",
"repository": { "repository": {
"type": "git", "type": "git",
"url": "https://gitee.com/dromara/MaxKey" "url": "https://gitee.com/dromara/MaxKey"

View File

@ -14,7 +14,6 @@
* limitations under the License. * limitations under the License.
*/ */
import { import {
HttpErrorResponse, HttpErrorResponse,
HttpEvent, HttpEvent,

View File

@ -1,24 +1,21 @@
<form nz-form [formGroup]="form" (ngSubmit)="submit()" role="form"> <form nz-form [formGroup]="form" (ngSubmit)="submit()" role="form">
<nz-radio-group <nz-radio-group [(ngModel)]="loginType" [ngModelOptions]="{ standalone: true }" nzSize="large" *ngIf="switchTab"
nzButtonStyle="solid" style="margin-bottom: 8px; width: 100%">
[(ngModel)]="loginType" <label nz-radio-button nzValue="normal" style="width: 50%; text-align: center">
[ngModelOptions]="{ standalone: true }"
style="margin-bottom: 8px; width: 100%"
nzSize="large"
>
<label nz-radio-button nzValue="normal" style="width: 33.3%; text-align: center">
<i nz-icon nzType="user" nzTheme="outline"></i> <i nz-icon nzType="user" nzTheme="outline"></i>
{{ 'mxk.login.tab-credentials' | i18n }}</label {{ 'mxk.login.tab-credentials' | i18n }}
> </label>
<label nz-radio-button nzValue="mobile" style="width: 33.3%; text-align: center" <label nz-radio-button nzValue="mobile" style="width: 50%; text-align: center" class="d-none">
><i nz-icon nzType="mobile" nzTheme="outline"></i>{{ 'mxk.login.tab-mobile' | i18n }}</label <i nz-icon nzType="mobile" nzTheme="outline"></i>
> {{ 'mxk.login.tab-mobile' | i18n }}
<label nz-radio-button nzValue="qrscan" style="width: 33.3%; text-align: center" (click)="getQrCode()"> </label>
<i nz-icon nzType="qrcode" nzTheme="outline"></i>{{ 'mxk.login.tab-qrscan' | i18n }}</label <label nz-radio-button nzValue="qrscan" style="width: 50%; text-align: center" (click)="getQrCode()">
> <i nz-icon nzType="qrcode" nzTheme="outline"></i>{{ 'mxk.login.tab-qrscan' | i18n }}
</label>
</nz-radio-group> </nz-radio-group>
<div nz-row *ngIf="loginType == 'normal'"> <div nz-row *ngIf="loginType == 'normal'">
<nz-alert style="width: 100%" *ngIf="error" [nzType]="'error'" [nzMessage]="error" [nzShowIcon]="true" class="mb-lg"></nz-alert> <nz-alert style="width: 100%" *ngIf="error" [nzType]="'error'" [nzMessage]="error" [nzShowIcon]="true"
class="mb-lg"></nz-alert>
<nz-form-item style="width: 100%"> <nz-form-item style="width: 100%">
<nz-form-control nzErrorTip=""> <nz-form-control nzErrorTip="">
<nz-input-group nzSize="large" nzPrefixIcon="user"> <nz-input-group nzSize="large" nzPrefixIcon="user">
@ -29,15 +26,12 @@
<nz-form-item style="width: 100%"> <nz-form-item style="width: 100%">
<nz-form-control nzErrorTip=""> <nz-form-control nzErrorTip="">
<nz-input-group [nzSuffix]="suffixTemplate" nzSize="large" nzPrefixIcon="key"> <nz-input-group [nzSuffix]="suffixTemplate" nzSize="large" nzPrefixIcon="key">
<input <input [type]="passwordVisible ? 'text' : 'password'" nz-input
[type]="passwordVisible ? 'text' : 'password'" placeholder="{{ 'mxk.login.text.password' | i18n }}" formControlName="password" />
nz-input
placeholder="{{ 'mxk.login.text.password' | i18n }}"
formControlName="password"
/>
</nz-input-group> </nz-input-group>
<ng-template #suffixTemplate> <ng-template #suffixTemplate>
<i nz-icon [nzType]="passwordVisible ? 'eye-invisible' : 'eye'" (click)="passwordVisible = !passwordVisible"></i> <i nz-icon [nzType]="passwordVisible ? 'eye-invisible' : 'eye'"
(click)="passwordVisible = !passwordVisible"></i>
</ng-template> </ng-template>
</nz-form-control> </nz-form-control>
</nz-form-item> </nz-form-item>
@ -74,7 +68,8 @@
<input nz-input formControlName="otpCaptcha" placeholder="{{ 'mxk.login.text.captcha' | i18n }}" /> <input nz-input formControlName="otpCaptcha" placeholder="{{ 'mxk.login.text.captcha' | i18n }}" />
</nz-input-group> </nz-input-group>
<ng-template #suffixSendOtpCodeButton> <ng-template #suffixSendOtpCodeButton>
<button type="button" nz-button nzSize="large" (click)="sendOtpCode()" [disabled]="count > 0" nzBlock [nzLoading]="loading"> <button type="button" nz-button nzSize="large" (click)="sendOtpCode()" [disabled]="count > 0" nzBlock
[nzLoading]="loading">
{{ count ? count + 's' : ('app.register.get-verification-code' | i18n) }} {{ count ? count + 's' : ('app.register.get-verification-code' | i18n) }}
</button> </button>
</ng-template> </ng-template>
@ -89,8 +84,8 @@
<label nz-checkbox formControlName="remember">{{ 'mxk.login.remember-me' | i18n }}</label> <label nz-checkbox formControlName="remember">{{ 'mxk.login.remember-me' | i18n }}</label>
</nz-col> </nz-col>
<nz-col [nzSpan]="12" class="text-right"> <nz-col [nzSpan]="12" class="text-right">
<a class="forgot" routerLink="/passport/forgot">{{ 'mxk.login.forgot-password' | i18n }}</a></nz-col <a class="forgot" routerLink="/passport/forgot">{{ 'mxk.login.forgot-password' | i18n }}</a>
> </nz-col>
</nz-form-item> </nz-form-item>
<nz-form-item *ngIf="loginType == 'normal' || loginType == 'mobile'"> <nz-form-item *ngIf="loginType == 'normal' || loginType == 'mobile'">
<button nz-button type="submit" nzType="primary" nzSize="large" [nzLoading]="loading" nzBlock> <button nz-button type="submit" nzType="primary" nzSize="large" [nzLoading]="loading" nzBlock>
@ -98,13 +93,12 @@
</button> </button>
</nz-form-item> </nz-form-item>
</form> </form>
<div class="other"> <div class="other" *ngIf="loginType == 'normal'">
{{ 'app.login.sign-in-with' | i18n }} {{ 'app.login.sign-in-with' | i18n }}
<ng-container *ngFor="let provd of socials.providers"> <ng-container *ngFor="let provd of socials.providers">
<i nz-tooltip nzTooltipTitle="{{ provd.providerName }}" (click)="socialauth(provd.provider)" nz-icon class="icon"> <i nz-tooltip nzTooltipTitle="{{ provd.providerName }}" (click)="socialauth(provd.provider)" nz-icon class="icon">
<img src="{{ provd.icon }}" style="width: 32px" /> <img src="{{ provd.icon }}" style="width: 32px" />
</i> </i>
</ng-container> </ng-container>
<a class="register" routerLink="/passport/register">{{ 'mxk.login.signup' | i18n }}</a> <a class="register d-none" routerLink="/passport/register">{{ 'mxk.login.signup' | i18n }}</a>
</div> </div>

View File

@ -22,6 +22,13 @@
padding-left: 4px; padding-left: 4px;
} }
.login-tab{
color: #000;
background: unset;
border-color: unset;
border-right-color: unset;
}
.icon { .icon {
margin-left: 16px; margin-left: 16px;
color: rgb(0 0 0 / 20%); color: rgb(0 0 0 / 20%);

View File

@ -50,13 +50,13 @@ export class UserLoginComponent implements OnInit, OnDestroy {
form: FormGroup; form: FormGroup;
error = ''; error = '';
switchTab = true;
loginType = 'normal'; loginType = 'normal';
loading = false; loading = false;
passwordVisible = false; passwordVisible = false;
imageCaptcha = ''; imageCaptcha = '';
captchaType = ''; captchaType = '';
state = ''; state = '';
count = 0; count = 0;
interval$: any; interval$: any;
@ -279,6 +279,7 @@ export class UserLoginComponent implements OnInit, OnDestroy {
// #region social // #region social
socialauth(provider: string): void { socialauth(provider: string): void {
this.authnService.clearUser();
this.socialsProviderService.authorize(provider).subscribe(res => { this.socialsProviderService.authorize(provider).subscribe(res => {
//console.log(res.data); //console.log(res.data);
window.location.href = res.data; window.location.href = res.data;

View File

@ -14,7 +14,6 @@
* limitations under the License. * limitations under the License.
*/ */
import { HttpClient } from '@angular/common/http'; import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { NzSafeAny } from 'ng-zorro-antd/core/types'; import { NzSafeAny } from 'ng-zorro-antd/core/types';

View File

@ -14,7 +14,6 @@
* limitations under the License. * limitations under the License.
*/ */
export function set2String(set: Set<String>): string { export function set2String(set: Set<String>): string {
let setValues = ''; let setValues = '';
set.forEach(value => { set.forEach(value => {

View File

@ -2,7 +2,7 @@
"name": "maxkey", "name": "maxkey",
"version": "3.5.0", "version": "3.5.0",
"description": "Leading-Edge IAM Identity and Access Management", "description": "Leading-Edge IAM Identity and Access Management",
"author": "MaxKey <maxkeysupport@163.com>", "author": "MaxKey <support@maxsso.net>",
"repository": { "repository": {
"type": "git", "type": "git",
"url": "https://gitee.com/dromara/MaxKey" "url": "https://gitee.com/dromara/MaxKey"