mirror of
https://github.com/chillzhuang/blade-tool
synced 2024-11-05 10:09:32 +08:00
🎉 2.7.2.RELEASE 集成JustAuth支持第三方登录
This commit is contained in:
parent
0b11e55f2c
commit
c63a6f469a
@ -1,7 +1,7 @@
|
||||
<p align="center">
|
||||
<img src="https://img.shields.io/badge/license-LGPL%20v3-blue.svg" alt="Build Status">
|
||||
<img src="https://img.shields.io/badge/Spring%20Cloud-Hoxton.SR5-blue.svg" alt="Coverage Status">
|
||||
<img src="https://img.shields.io/badge/Spring%20Boot-2.2.7.RELEASE-blue.svg" alt="Downloads">
|
||||
<img src="https://img.shields.io/badge/Spring%20Cloud-Hoxton.SR7-blue.svg" alt="Coverage Status">
|
||||
<img src="https://img.shields.io/badge/Spring%20Boot-2.2.9.RELEASE-blue.svg" alt="Downloads">
|
||||
</p>
|
||||
|
||||
## SpringBlade微服务开发平台
|
||||
|
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>org.springblade</groupId>
|
||||
<artifactId>blade-tool</artifactId>
|
||||
<version>2.7.1</version>
|
||||
<version>2.7.2</version>
|
||||
</parent>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
@ -27,6 +27,7 @@ import java.io.InputStream;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
/**
|
||||
* Spring boot 控制器 请求日志,方便代码调试
|
||||
@ -66,6 +67,7 @@ public class RequestLogAspect {
|
||||
continue;
|
||||
}
|
||||
RequestBody requestBody = methodParam.getParameterAnnotation(RequestBody.class);
|
||||
String parameterName = methodParam.getParameterName();
|
||||
Object value = args[i];
|
||||
// 如果是body的json则是对象
|
||||
if (requestBody != null && value != null) {
|
||||
@ -89,6 +91,19 @@ public class RequestLogAspect {
|
||||
} else if (value instanceof HttpServletResponse) {
|
||||
} else if (value instanceof InputStream) {
|
||||
} else if (value instanceof InputStreamSource) {
|
||||
} else if (value instanceof List) {
|
||||
List<?> list = (List<?>) value;
|
||||
AtomicBoolean isSkip = new AtomicBoolean(false);
|
||||
for (Object o : list) {
|
||||
if ("StandardMultipartFile".equalsIgnoreCase(o.getClass().getSimpleName())) {
|
||||
isSkip.set(true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (isSkip.get()) {
|
||||
paraMap.put(parameterName, "此参数不能序列化为json");
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
// 参数名
|
||||
RequestParam requestParam = methodParam.getParameterAnnotation(RequestParam.class);
|
||||
|
@ -97,7 +97,7 @@ mybatis-plus:
|
||||
swagger:
|
||||
title: SpringBlade 接口文档系统
|
||||
description: SpringBlade 接口文档系统
|
||||
version: 2.7.1
|
||||
version: 2.7.2
|
||||
license: Powered By SpringBlade
|
||||
licenseUrl: https://bladex.vip
|
||||
terms-of-service-url: https://bladex.vip
|
||||
|
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>blade-tool</artifactId>
|
||||
<groupId>org.springblade</groupId>
|
||||
<version>2.7.1</version>
|
||||
<version>2.7.2</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>blade-tool</artifactId>
|
||||
<groupId>org.springblade</groupId>
|
||||
<version>2.7.1</version>
|
||||
<version>2.7.2</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>blade-tool</artifactId>
|
||||
<groupId>org.springblade</groupId>
|
||||
<version>2.7.1</version>
|
||||
<version>2.7.2</version>
|
||||
</parent>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
@ -25,7 +25,7 @@ public interface AppConstant {
|
||||
/**
|
||||
* 应用版本
|
||||
*/
|
||||
String APPLICATION_VERSION = "2.7.1";
|
||||
String APPLICATION_VERSION = "2.7.2";
|
||||
|
||||
/**
|
||||
* 基础包
|
||||
|
@ -36,6 +36,7 @@ public interface TokenConstant {
|
||||
String USER_NAME = "user_name";
|
||||
String ROLE_NAME = "role_name";
|
||||
String TENANT_ID = "tenant_id";
|
||||
String OAUTH_ID = "oauth_id";
|
||||
String CLIENT_ID = "client_id";
|
||||
String LICENSE = "license";
|
||||
String LICENSE_NAME = "powered by blade";
|
||||
|
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>blade-tool</artifactId>
|
||||
<groupId>org.springblade</groupId>
|
||||
<version>2.7.1</version>
|
||||
<version>2.7.2</version>
|
||||
</parent>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>blade-tool</artifactId>
|
||||
<groupId>org.springblade</groupId>
|
||||
<version>2.7.1</version>
|
||||
<version>2.7.2</version>
|
||||
</parent>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>blade-tool</artifactId>
|
||||
<groupId>org.springblade</groupId>
|
||||
<version>2.7.1</version>
|
||||
<version>2.7.2</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>blade-tool</artifactId>
|
||||
<groupId>org.springblade</groupId>
|
||||
<version>2.7.1</version>
|
||||
<version>2.7.2</version>
|
||||
</parent>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
@ -15,6 +15,8 @@
|
||||
*/
|
||||
package org.springblade.core.secure;
|
||||
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
@ -33,6 +35,13 @@ public class AuthInfo {
|
||||
private String tokenType;
|
||||
@ApiModelProperty(value = "刷新令牌")
|
||||
private String refreshToken;
|
||||
@ApiModelProperty(value = "用户ID")
|
||||
@JsonSerialize(using = ToStringSerializer.class)
|
||||
private Long userId;
|
||||
@ApiModelProperty(value = "租户ID")
|
||||
private String tenantId;
|
||||
@ApiModelProperty(value = "第三方系统ID")
|
||||
private String oauthId;
|
||||
@ApiModelProperty(value = "头像")
|
||||
private String avatar = "https://gw.alipayobjects.com/zos/rmsportal/BiazfanxmamNRoxxVxka.png";
|
||||
@ApiModelProperty(value = "角色名")
|
||||
|
36
blade-core-social/pom.xml
Normal file
36
blade-core-social/pom.xml
Normal file
@ -0,0 +1,36 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>blade-tool</artifactId>
|
||||
<groupId>org.springblade</groupId>
|
||||
<version>2.7.2</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>blade-core-social</artifactId>
|
||||
<name>${project.artifactId}</name>
|
||||
<version>${blade.tool.version}</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<dependencies>
|
||||
<!--Blade-->
|
||||
<dependency>
|
||||
<groupId>org.springblade</groupId>
|
||||
<artifactId>blade-core-tool</artifactId>
|
||||
<version>${blade.tool.version}</version>
|
||||
</dependency>
|
||||
<!-- 第三方登陆 -->
|
||||
<dependency>
|
||||
<groupId>me.zhyd.oauth</groupId>
|
||||
<artifactId>JustAuth</artifactId>
|
||||
<version>1.15.6</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>httpclient</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
@ -0,0 +1,44 @@
|
||||
/**
|
||||
* Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
|
||||
* <p>
|
||||
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* <p>
|
||||
* http://www.gnu.org/licenses/lgpl.html
|
||||
* <p>
|
||||
* 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.
|
||||
*/
|
||||
package org.springblade.core.social.config;
|
||||
|
||||
import com.xkcoding.http.HttpUtil;
|
||||
import com.xkcoding.http.support.Http;
|
||||
import com.xkcoding.http.support.httpclient.HttpClientImpl;
|
||||
import org.springblade.core.social.props.SocialProperties;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* SocialConfiguration
|
||||
*
|
||||
* @author Chill
|
||||
*/
|
||||
@Configuration
|
||||
@EnableConfigurationProperties(SocialProperties.class)
|
||||
public class SocialConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(Http.class)
|
||||
public Http simpleHttp() {
|
||||
HttpClientImpl httpClient = new HttpClientImpl();
|
||||
HttpUtil.setHttp(httpClient);
|
||||
return httpClient;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
/**
|
||||
* Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
|
||||
* <p>
|
||||
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* <p>
|
||||
* http://www.gnu.org/licenses/lgpl.html
|
||||
* <p>
|
||||
* 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.
|
||||
*/
|
||||
package org.springblade.core.social.props;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import me.zhyd.oauth.config.AuthConfig;
|
||||
import me.zhyd.oauth.config.AuthDefaultSource;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* SocialProperties
|
||||
*
|
||||
* @author Chill
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@ConfigurationProperties(prefix = "social")
|
||||
public class SocialProperties {
|
||||
|
||||
/**
|
||||
* 启用
|
||||
*/
|
||||
private Boolean enabled = false;
|
||||
|
||||
/**
|
||||
* 域名地址
|
||||
*/
|
||||
private String domain;
|
||||
|
||||
/**
|
||||
* 类型
|
||||
*/
|
||||
private Map<AuthDefaultSource, AuthConfig> oauth = Maps.newHashMap();
|
||||
|
||||
/**
|
||||
* 别名
|
||||
*/
|
||||
private Map<String, String> alias = Maps.newHashMap();
|
||||
|
||||
}
|
@ -0,0 +1,150 @@
|
||||
/**
|
||||
* Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
|
||||
* <p>
|
||||
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* <p>
|
||||
* http://www.gnu.org/licenses/lgpl.html
|
||||
* <p>
|
||||
* 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.
|
||||
*/
|
||||
package org.springblade.core.social.utils;
|
||||
|
||||
import me.zhyd.oauth.config.AuthConfig;
|
||||
import me.zhyd.oauth.config.AuthDefaultSource;
|
||||
import me.zhyd.oauth.exception.AuthException;
|
||||
import me.zhyd.oauth.request.*;
|
||||
import org.springblade.core.social.props.SocialProperties;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* SocialUtil
|
||||
*
|
||||
* @author Chill
|
||||
*/
|
||||
public class SocialUtil {
|
||||
|
||||
/**
|
||||
* 根据具体的授权来源,获取授权请求工具类
|
||||
*
|
||||
* @param source 授权来源
|
||||
* @return AuthRequest
|
||||
*/
|
||||
public static AuthRequest getAuthRequest(String source, SocialProperties socialProperties) {
|
||||
AuthDefaultSource authSource = Objects.requireNonNull(AuthDefaultSource.valueOf(source.toUpperCase()));
|
||||
AuthConfig authConfig = socialProperties.getOauth().get(authSource);
|
||||
if (authConfig == null) {
|
||||
throw new AuthException("未获取到有效的Auth配置");
|
||||
}
|
||||
AuthRequest authRequest = null;
|
||||
switch (authSource) {
|
||||
case GITHUB:
|
||||
authRequest = new AuthGithubRequest(authConfig);
|
||||
break;
|
||||
case GITEE:
|
||||
authRequest = new AuthGiteeRequest(authConfig);
|
||||
break;
|
||||
case OSCHINA:
|
||||
authRequest = new AuthOschinaRequest(authConfig);
|
||||
break;
|
||||
case QQ:
|
||||
authRequest = new AuthQqRequest(authConfig);
|
||||
break;
|
||||
case WECHAT_OPEN:
|
||||
authRequest = new AuthWeChatOpenRequest(authConfig);
|
||||
break;
|
||||
case WECHAT_ENTERPRISE:
|
||||
authRequest = new AuthWeChatEnterpriseRequest(authConfig);
|
||||
break;
|
||||
case WECHAT_MP:
|
||||
authRequest = new AuthWeChatMpRequest(authConfig);
|
||||
break;
|
||||
case DINGTALK:
|
||||
authRequest = new AuthDingTalkRequest(authConfig);
|
||||
break;
|
||||
case ALIPAY:
|
||||
// 支付宝在创建回调地址时,不允许使用localhost或者127.0.0.1,所以这儿的回调地址使用的局域网内的ip
|
||||
authRequest = new AuthAlipayRequest(authConfig);
|
||||
break;
|
||||
case BAIDU:
|
||||
authRequest = new AuthBaiduRequest(authConfig);
|
||||
break;
|
||||
case WEIBO:
|
||||
authRequest = new AuthWeiboRequest(authConfig);
|
||||
break;
|
||||
case CODING:
|
||||
authRequest = new AuthCodingRequest(authConfig);
|
||||
break;
|
||||
case CSDN:
|
||||
authRequest = new AuthCsdnRequest(authConfig);
|
||||
break;
|
||||
case TAOBAO:
|
||||
authRequest = new AuthTaobaoRequest(authConfig);
|
||||
break;
|
||||
case GOOGLE:
|
||||
authRequest = new AuthGoogleRequest(authConfig);
|
||||
break;
|
||||
case FACEBOOK:
|
||||
authRequest = new AuthFacebookRequest(authConfig);
|
||||
break;
|
||||
case DOUYIN:
|
||||
authRequest = new AuthDouyinRequest(authConfig);
|
||||
break;
|
||||
case LINKEDIN:
|
||||
authRequest = new AuthLinkedinRequest(authConfig);
|
||||
break;
|
||||
case MICROSOFT:
|
||||
authRequest = new AuthMicrosoftRequest(authConfig);
|
||||
break;
|
||||
case MI:
|
||||
authRequest = new AuthMiRequest(authConfig);
|
||||
break;
|
||||
case TOUTIAO:
|
||||
authRequest = new AuthToutiaoRequest(authConfig);
|
||||
break;
|
||||
case TEAMBITION:
|
||||
authRequest = new AuthTeambitionRequest(authConfig);
|
||||
break;
|
||||
case PINTEREST:
|
||||
authRequest = new AuthPinterestRequest(authConfig);
|
||||
break;
|
||||
case RENREN:
|
||||
authRequest = new AuthRenrenRequest(authConfig);
|
||||
break;
|
||||
case STACK_OVERFLOW:
|
||||
authRequest = new AuthStackOverflowRequest(authConfig);
|
||||
break;
|
||||
case HUAWEI:
|
||||
authRequest = new AuthHuaweiRequest(authConfig);
|
||||
break;
|
||||
case KUJIALE:
|
||||
authRequest = new AuthKujialeRequest(authConfig);
|
||||
break;
|
||||
case GITLAB:
|
||||
authRequest = new AuthGitlabRequest(authConfig);
|
||||
break;
|
||||
case MEITUAN:
|
||||
authRequest = new AuthMeituanRequest(authConfig);
|
||||
break;
|
||||
case ELEME:
|
||||
authRequest = new AuthElemeRequest(authConfig);
|
||||
break;
|
||||
case TWITTER:
|
||||
authRequest = new AuthTwitterRequest(authConfig);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (null == authRequest) {
|
||||
throw new AuthException("未获取到有效的Auth配置");
|
||||
}
|
||||
return authRequest;
|
||||
}
|
||||
|
||||
}
|
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>blade-tool</artifactId>
|
||||
<groupId>org.springblade</groupId>
|
||||
<version>2.7.1</version>
|
||||
<version>2.7.2</version>
|
||||
</parent>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
@ -55,7 +55,7 @@ public class SwaggerProperties {
|
||||
/**
|
||||
* 版本
|
||||
**/
|
||||
private String version = "2.7.1";
|
||||
private String version = "2.7.2";
|
||||
/**
|
||||
* 许可证
|
||||
**/
|
||||
|
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>org.springblade</groupId>
|
||||
<artifactId>blade-tool</artifactId>
|
||||
<version>2.7.1</version>
|
||||
<version>2.7.2</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>org.springblade</groupId>
|
||||
<artifactId>blade-tool</artifactId>
|
||||
<version>2.7.1</version>
|
||||
<version>2.7.2</version>
|
||||
</parent>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>blade-tool</artifactId>
|
||||
<groupId>org.springblade</groupId>
|
||||
<version>2.7.1</version>
|
||||
<version>2.7.2</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
13
pom.xml
13
pom.xml
@ -5,7 +5,7 @@
|
||||
|
||||
<groupId>org.springblade</groupId>
|
||||
<artifactId>blade-tool</artifactId>
|
||||
<version>2.7.1</version>
|
||||
<version>2.7.2</version>
|
||||
<packaging>pom</packaging>
|
||||
<name>blade-tool</name>
|
||||
<description>
|
||||
@ -36,23 +36,23 @@
|
||||
</scm>
|
||||
|
||||
<properties>
|
||||
<blade.tool.version>2.7.1</blade.tool.version>
|
||||
<blade.tool.version>2.7.2</blade.tool.version>
|
||||
|
||||
<java.version>1.8</java.version>
|
||||
<maven.plugin.version>3.8.0</maven.plugin.version>
|
||||
<swagger.version>2.9.2</swagger.version>
|
||||
<swagger.models.version>1.5.21</swagger.models.version>
|
||||
<knife4j.version>2.0.3</knife4j.version>
|
||||
<knife4j.version>2.0.4</knife4j.version>
|
||||
<mybatis.plus.version>3.3.2</mybatis.plus.version>
|
||||
<protostuff.version>1.6.0</protostuff.version>
|
||||
<disruptor.version>3.4.2</disruptor.version>
|
||||
<spring.boot.admin.version>2.2.3</spring.boot.admin.version>
|
||||
<spring.boot.admin.version>2.3.0</spring.boot.admin.version>
|
||||
<mica.auto.version>1.1.0</mica.auto.version>
|
||||
<alibaba.cloud.version>2.2.1.RELEASE</alibaba.cloud.version>
|
||||
<alibaba.seata.version>1.3.0</alibaba.seata.version>
|
||||
|
||||
<spring.boot.version>2.2.7.RELEASE</spring.boot.version>
|
||||
<spring.cloud.version>Hoxton.SR5</spring.cloud.version>
|
||||
<spring.boot.version>2.2.9.RELEASE</spring.boot.version>
|
||||
<spring.cloud.version>Hoxton.SR7</spring.cloud.version>
|
||||
<spring.platform.version>Cairo-SR8</spring.platform.version>
|
||||
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
@ -67,6 +67,7 @@
|
||||
<module>blade-core-log</module>
|
||||
<module>blade-core-mybatis</module>
|
||||
<module>blade-core-secure</module>
|
||||
<module>blade-core-social</module>
|
||||
<module>blade-core-swagger</module>
|
||||
<module>blade-core-test</module>
|
||||
<module>blade-core-tool</module>
|
||||
|
Loading…
Reference in New Issue
Block a user