프로젝트 분석 NiterForum (1) 프로젝트 시작 및 로그인

기사 디렉토리


gitee: NiterForum 흙손

시작

속성 파일 인코딩 문제 : (46개 메시지) Intellij IDEA 2018 속성 파일 유니코드를 중국어 settings_properties 파일\u6d4f\u89c8\u5668\u8868\u5355\u5185\u_Program 새 비전 블로그-CSDN 블로그

SSL 인증서 신청 및 다운로드 : 알리바바 클라우드 또는 텐센트 클라우드에서 SSL 인증서 서비스를 찾아 신청만 하면 됩니다. (사전 도메인 이름 신청 필요)
여기에 이미지 설명 삽입

HTTPS를 사용하지 않는 경우 :

application.properties 수정

#http端口号 80
# server.custom.httpPort=80
#https加密端口号 443
server.port=80
#SSL证书路径 一定要加上classpath:
# server.ssl.key-store=classpath:niter_cn.jks
#SSL证书密码
# server.ssl.key-store-password=***
#证书类型
# server.ssl.key-store-type=JKS

cn/niter/forum/config/HttpsConfig.java파일을 삭제하거나 그 안의 코드를 주석 처리하십시오.

다음 메타 태그를 제거하십시오 resources/templates/common/header.html.

<meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">

cn/niter/forum/util/CookieUtils.java삭제

cookie.setHttpOnly(true);//通过js脚本是无法获取到cookie的信息的。防止XSS攻击。

맞춤 정보 :

사이트 정보, 메타 태그, 연락처 정보, 검색 엔진 검증 태그, 사용자 그룹 레벨 이름 및 상한 포인트, 포인트 이름 및 가중치, 사용자 행동 포인트 보상, 뉴스 상담 인터페이스(건너뛰기 가능), 사용자 정의 속성 파일의 제스처 검증 코드 서비스(VAPTCHA) ), SMS관련 상품, 텐센트 기업우편함(개인우편함 이용가능), 깃허브 로그인

사이트 정보:

#这项非常重要,请务必准确填写域名、ip或者localhost,不要加http(s)://,以及后面的/。
site.main.domain=localhost

인증코드 서비스는 https://www.vaptcha.com/에 접속하여 인증단위 생성 도메인명이 local인 경우 localhost 입력 후 속성에 VID, KEY 복사

여기에 이미지 설명 삽입

#手势验证码vaptcha的vid与key,请去官网获取https://www.vaptcha.com/ 。也可以使用自己选用验证码服务,但需要修改源码!
vaptcha.vid=***
vaptcha.key=***
#腾讯企业邮箱相关配置信息,请去官网获取https://exmail.qq.com/ 。也可以使用自己的邮箱账号。修改成对应信息即可!
exmail.account=***
exmail.password=***
exmail.smtp.host=smtp.exmail.qq.com

깃허브 로그인

[외부 링크 이미지 전송 실패, 소스 사이트에 거머리 방지 메커니즘이 있을 수 있습니다. 이미지를 저장하고 직접 업로드하는 것이 좋습니다. (img-amFftk78-1681345753492) typora-user-images\ image-20230403151342356.png)]

#github登录 API配置信息。请去这里创建应用即可,秒审核,轻松配置 https://github.com/settings/applications/new
github.client.id=***
github.client.secret=***
github.redirect.uri=http(s)://localhost/callback

바이두 로그인

여기에 이미지 설명 삽입

#百度登录 API配置信息。请去这里创建应用即可,秒审核,轻松配置 http://developer.baidu.com/console#app/create
baidu.client.id=***
baidu.client.secret=***
baidu.redirect.uri=http(s)://localhost/callbackbaidu

웨이보 로그인

#微博登录 API配置信息。请去这里创建应用即可,审核需要域名,无需备案  https://open.weibo.com/apps/new?sort=web
weibo.client.id=***
weibo.client.secret=***
weibo.redirect.uri=http://localhost/callbackweibo

QQ 로그인

#QQ登录 API配置信息。请去这里创建应用即可,审核需要域名,如申请国际域名接入,无需备案  https://connect.qq.com/manage.html#/appcreate/web
qq.client.id=***
qq.client.secret=***
qq.redirect.uri=http(s)://yourdomain/callbackqq

데이터베이스 구성 수정 :

#数据库配置,填写你自己的
spring.datasource.url=jdbc:mysql://localhost:3306/***
spring.datasource.username=***
spring.datasource.password=***

#数据库配置2,按需修改。如不熟悉,不建议修改
spring.datasource.hikari.connection-init-sql=set names utf8mb4;
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.hikari.minimum-idle=3
spring.datasource.hikari.maximum-pool-size=10
spring.datasource.hikari.max-lifetime =30000
mybatis.configuration.map-underscore-to-camel-case=true
mybatis.type-aliases-package=cn.niter.forum.mapper
mybatis.mapper-locations=classpath:mapper/*.xml

/resource/generatorConfig.xml수정 위치 :

		<plugin type="org.mybatis.generator.plugins.RowBoundsPlugin"></plugin>
        <jdbcConnection driverClass="com.mysql.jdbc.Driver"
                        connectionURL="jdbc:mysql://localhost:3306/niter"
                        userId="***"
                        password="****">
        </jdbcConnection>

객체 스토리지 구성:

여기에 이미지 설명 삽입

#腾讯云账户设置
qcloud.secret-id=***
qcloud.secret-key=***
#是否开启关键字自动生成,enable默认为0关闭;改为1开启
qcloud.keywords.enable=0
#是否开启数据万象功能,enable默认为0关闭;改为1开启。该功能用于上传图片的审核、压缩(仅限jpg)、水印生成,也可用于头像的剪切
qcloud.ci.enable=0
#数据万象的访问域名,最后斜杠不能省
qcloud.ci.objecturl=https://qcdn2.niter.cn/
#腾讯云对象存储配置,修改成你自己的。也可以自选对象存储服务,但需要修改源码!
qcloud.cos.bucket-name=niter-1251590924
qcloud.cos.region=ap-nanjing
#这是你对象存储的访问域名,最后斜杠不能省。
qcloud.cos.objecturl=https://qcdn.niter.cn/
qcloud.sms.appId=1400000000
qcloud.sms.sign=尼特IT
qcloud.sms.tempId=200000

기타 구성:

#是否开启tinify png压缩功能,注意压缩需要时间等待,可配合压缩阈值根据需要开启关闭,默认0关闭,1开启
tinify.enable=0
#请于此处https://tinify.cn/developers 注册开发者账号,即可每月免费压缩500张,填写获取到的key
tinify.key=sadfdg
#压缩阈值,超过这个长度才压缩,否则不压缩,默认1M
tinify.minContentLength=1024000

#百度云内容审核 https://ai.baidu.com/tech/textcensoring
#是否开启内容审核自动生成,enable默认为0关闭;改为1开启
baiducloud.censor.enable=0
baiducloud.censor.appid=12345678
baiducloud.censor.apikey=***
baiducloud.censor.secretkey=***

#其它配置,按需修改,如不熟悉。不建议修改
logging.file=logs/community.log
logging.level.root=info
logging.file.max-history=15
logging.file.max-size=100MB
server.servlet.session.timeout=15552000
spring.mvc.favicon.enabled=false
spring.servlet.multipart.max-file-size=5MB
spring.servlet.multipart.max-request-size=10MB
spring:
thymeleaf:
cache: false
mode: LEGACYHTML5

#resource
# 启用缓存
spring.resources.chain.cache=true
# 资源缓存时间,单位秒-缓存7天
spring.resources.cache.period=604800

오류 수정 :

cn.niter.forum.provider.QCloudProvider에서 :

// import sun.misc.BASE64Encoder;
import org.apache.commons.codec.binary.Base64;

// String encodeBase64 = new BASE64Encoder().encode(data);
String encodeBase64 = Base64.encodeBase64String(data);

프로젝트에서 64비트 인코딩으로 설계합니다. 때때로 개발은 JDK와 함께 제공되는 BASE64 도구를 사용합니다 . 그러나 썬컴퍼니는 그렇게 하지 않는 것이 좋습니다. 특히 JDK 버전이 업데이트되면 프로젝트에 저장된 정보까지 포함됩니다. 교체를 위해 import org.apache.commons.codec.binary.Base64를 참조할 수 있습니다.

(46 메시지) java - IDE_Sugar_ya의 블로그-CSDN 블로그에서 sun.misc.BASE64Encoder jar 패키지 및 sun.misc.Base64Decoder jar 패키지를 찾을 수 없습니다.

mysql은 버전 5를 사용합니다.

페이지의 js는 비엔티안 데이터를 요청하는 워터마크 서비스로 작성되었습니다. 활성화되지 않은 경우 잘못된 요청 경로가 전송됩니다.

https://.../upload/user/2/img/20230403174530_gh.jpeg # 没开启,正确
https://.../upload/user/2/img/20230403174530_gh.jpeg/water_mark # 没开启,错误

수정 /resource/templates/t/index.html:

// str = str + "<img data-id=" + item.id + "  layer-src=\"" + item.imageUrls[j] + "/watermark_text\" src=\"" + item.imageUrls[j] + "/t_small\">";

str = str + "<img data-id=" + item.id + "  layer-src=\"" + item.imageUrls[j] + "\" src=\"" + item.imageUrls[j] + "\">";

로그인

홈페이지 방문

먼저 IndexController.forum 메서드를 입력합니다.

로그인 상태 확인, 상위 질문 및 질문 목록 처리, 인기 태그 및 등록 사용자 사용 캐시(목록)

로그인-정보입력-인간-기계검증 클릭 후 ValidateController#post 메소드('/validate', post)를 통과 후 입력합니다. 게시 방법, 액세스 토큰 제출, 장면, IP

여기서 ExpiringMap맵 .

ExpiringMap<String,String> interval = ExpiringMap.builder() // 存ip, token
    .maxSize(20)//设置最大容量,增大攻击难度,值越大存储的可疑ip越多,过大会占用额外资源
    .expiration(30, TimeUnit.SECONDS)//过期时间30秒
    .expirationPolicy(ExpirationPolicy.CREATED)//每次访问重置过期时间
    .variableExpiration()
    .build();

ExpiringMap<String,Integer> ipScores = ExpiringMap.builder() // 存ip, scene
    .maxSize(100)//设置最大容量,增大攻击难度,值越大存储的可疑ip越多,过大会占用额外资源
    .expiration(1, TimeUnit.DAYS)//过期时间1天
    .expirationPolicy(ExpirationPolicy.CREATED)//每次更新重置过期时间
    .variableExpiration()
    .build();

ExpiringMap 함수:

1. 지도의 항목은 일정 기간 후에 자동으로 만료되도록 설정할 수 있습니다.
2. Map의 최대 용량 값을 설정할 수 있으며 최대 크기에 도달했을 때 값을 다시 삽입하면 Map의 첫 번째 값이 만료됩니다.
3. 청취 이벤트를 추가하고 항목이 만료되면 청취 기능을 예약할 수 있습니다.
4. get() 메서드 호출 시 객체를 생성하도록 지연 로딩을 설정할 수 있습니다.

그런 다음 두 번째 인간-기계 검증을 VaptchaProvider.getValidateResult(token,scene,ip)수행하는 데

Ctrl + Alt + H 를 UserService.registerOrLoginWithMail사용 메서드 호출 체인을 보고, SsoApi.registerOrLoginWithMail 호출을 찾고, 이 클래스에서 '/login' 요청에 대한 매핑 메서드 로그인을 찾습니다.

요점은 다음과 같습니다. selectByExample 사용

(48 메시지) 일반적으로 selectByExample 사용 Mapper_ccity86155의 블로그-CSDN 블로그

/*
Example 查询范例
Criteria 查询标准,Example的静态内部类
*/
Example example=new Example(要查询的表对应的实体类.class);
Example.Criteria criteria=example.createCriteria();//创建查询标准
criteria.andEqualTo("字段","值");//调用方法,编写自己想要查询的条件
List list=userMapper.selectByExample(example);
List list=userMapper.selectByExampleAndRowBounds(example,new RowBounds(0,2));// 指定获取几条特定的查询语句,类似于limit。可以在分页的时候使用

그리고 JWT :

resultDTO.setData(tokenUtils.getToken(getUserDTO(users.get(0))));
                -----------------^
                |
public String getToken(UserDTO user) {
    
    
        String token = "";
        token = JWT.create()
                .withIssuer("NiterUser")
                //.withAudience(""+user.getId())// 将 user id 保存到 token 里面
                .withClaim("name", user.getName())
                .withClaim("id",user.getId())
                //.withClaim("userId",""+user.getId())
                .withClaim("avatarUrl",user.getAvatarUrl())
                .withClaim("groupId",user.getGroupId())
                .withClaim("vipRank",user.getVipRank())
                .withExpiresAt(new Date(System.currentTimeMillis() + 3600000 * 24 * 3))//三天
                .sign(Algorithm.HMAC256(SECRET));// 以 password 作为 token 的签名/密钥
        return token;
}

인터셉터(AOP 프로그래밍, 인터셉트 "/**")에는 토큰을 확인하기 위한 다음 코드가 있습니다.

HandlerMethod handlerMethod=(HandlerMethod)handler;
Method method=handlerMethod.getMethod();
String token=null;
ResultDTO resultDTO=null;
Cookie[] cookies = request.getCookies();
boolean hashToken = false;
if(cookies!=null&&cookies.length!=0){
    
    
    for (Cookie cookie : cookies) {
    
    
        if(cookie.getName().equals("token")){
    
     
            token=cookie.getValue(); // 获取cookie里的tocken
            if(token!=null) {
    
    
                hashToken=true; // 标记tocken有值
                resultDTO = tokenUtils.verifyToken(token); // 验证tocken
                if(resultDTO.getCode()==200){
    
     // 成功
                    UserDTO userDTO = (UserDTO) resultDTO.getData();
                    request.setAttribute("loginUser",userDTO);
                    loginUserCache.putLoginUser(userDTO.getId(),
                                                System.currentTimeMillis());//写入loginCache 
                }
            }
            break;
        }
    }
}

if (method.isAnnotationPresent(UserLoginToken.class)) {
    
     //如果请求的映射方法有自定义注解
    UserLoginToken userLoginToken = method.getAnnotation(UserLoginToken.class);
    if (userLoginToken.required()) {
    
     // 注解的required属性为true(需要认证)
        // 执行认证
        if ((!hashToken)||resultDTO.getCode()!=200) {
    
    
            throw new CustomizeException(CustomizeErrorCode.NO_LOGIN);
        }
    }
}
// 自定义注解
@Target({
    
    ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface UserLoginToken {
    
    
    boolean required() default true;
}

여기에 이미지 설명 삽입

자세한 내용은 JWT 상세 튜토리얼 및 Use_jwt Tutorial_이상적인 달새가 있는 블로그를 참조하세요.

그런 다음 홈페이지로 이동하여 홈페이지 게시물 표시 및 사용자 메시지 프롬프트(""/api/notification/mine" 요청)를 처리합니다.

추천

출처blog.csdn.net/Falling_Asteroid/article/details/130121319