欧美free性护士vide0shd,老熟女,一区二区三区,久久久久夜夜夜精品国产,久久久久久综合网天天,欧美成人护士h版

首頁綜合 正文
目錄

柚子快報激活碼778899分享:java 簡歷項(xiàng)目知識,八股文

柚子快報激活碼778899分享:java 簡歷項(xiàng)目知識,八股文

http://yzkb.51969.com/

關(guān)于簡歷項(xiàng)目

基本網(wǎng)絡(luò)知識

TCP協(xié)議

傳輸控制協(xié)議

三次握手

客戶機(jī)發(fā)送連接請求報文段到服務(wù)器,并進(jìn)入SYN_SENT狀態(tài),等待服務(wù)器確認(rèn)(SYN = 1,seq = x) 服務(wù)器收到連接請求報文,如果同意建立連接,向客戶機(jī)發(fā)回確認(rèn)報文段,并為該TCP連接分配TCP緩存和變量(SYN = 1,ACK = 1,seq = y,ack = x+1) 客戶機(jī)收到服務(wù)器的確認(rèn)報文段后,向服務(wù)器給出確認(rèn)報文段,并且也要給該連接分配緩存和變量,此包發(fā)送完畢,客戶端和服務(wù)器進(jìn)入ESTABLISHED(TCP連接成功)狀態(tài),完成三次握手

四次揮手

TCP客戶端發(fā)送一個FIN,用來關(guān)閉客戶端到服務(wù)器的數(shù)據(jù)傳輸 服務(wù)器收到這個FIN,它發(fā)回一個ACK,確認(rèn)序號為收到的序號+1。和SYN一樣,一個FIN將占用一個序號 服務(wù)器關(guān)閉客戶端的連接,發(fā)送一個FIN給客戶端 客戶端發(fā)回ACK報文確認(rèn),并將確認(rèn)序號設(shè)置為收到序號+1

TCP握手為什么不能是兩次

防止兩次握手的情況下已經(jīng)失效的連接請求報文段突然又傳送到服務(wù)端而產(chǎn)生錯誤

HTTP請求中的GET和POST方法的區(qū)別

主要區(qū)別在于GET方法是請求讀取由URL所標(biāo)志的信息,POST是給服務(wù)器添加信息。

報文:get請求放在url,post請求放在報文體中,部分瀏覽器對URL長度有限制

Cookie和Session的區(qū)別

cookie數(shù)據(jù)保存在客戶端,session數(shù)據(jù)保存在服務(wù)器端 都可以存放敏感信息 cookie和session都是用來跟蹤瀏覽器用戶身份的會話方式 cookie保存在客戶機(jī)硬盤上,session默認(rèn)被保存在服務(wù)器的一個文件夾里(不是內(nèi)存) session的運(yùn)行依賴sessionId,而sessionId是存放在cookie中的,也就是說,如果瀏覽器禁用了cookie,同時session也會失效,但可以通過URL傳遞sessionId session可以存放在文件、數(shù)據(jù)庫、內(nèi)存中都可以 用戶驗(yàn)證這種場合一般會用session

博客項(xiàng)目

前后端的技術(shù)棧

前端是vue,在最近的一次修改中使用echarts線性表格來展示某一時間段的文章瀏覽量。

后端使用springboot、springsecurity、swagger、mybatisplus、Redis等。

SpringSecurity核心功能

認(rèn)證(Authentication) : 驗(yàn)證用戶身份的過程 授權(quán)(Authorization):確認(rèn)用戶權(quán)限 防護(hù)攻擊:如跨域請求偽造CSRF和跨站腳本攻擊XSS Servlet API集成:與Java Servlet API無縫集成,提供web安全功能 可擴(kuò)展性:通過自定義組件和擴(kuò)展點(diǎn)可輕松擴(kuò)展springSecurity

springSecurity的架構(gòu)

由以下組件組成:

securityContextHolder:存儲與當(dāng)前線程關(guān)聯(lián)的安全上下文。 Authentication:表示用戶的認(rèn)證信息。 UserDetails:表示用戶的詳細(xì)信息。 AuthenticationManager:負(fù)責(zé)處理認(rèn)證請求。 AccessDecisionManager:負(fù)責(zé)授權(quán)決策 FilterChainProxy:負(fù)責(zé)處理Http請求的過濾器鏈。 SecurityFilterChain:由一系列安全過濾器組成的鏈。

什么是SecurityContextHolder

securityContextHolder是一個用于存儲與當(dāng)前線程相關(guān)的安全上下文的類,它使用ThreadLocal機(jī)制來存儲當(dāng)前用戶的認(rèn)證信息,如Authentication對象。

springsecurity登錄如何實(shí)現(xiàn)

@Service

public class LoginServiceImpl implements LoginServcie {

?

? ?@Autowired

? ?private AuthenticationManager authenticationManager;

? ?@Autowired

? ?private RedisCache redisCache;

?

? ?@Override

? ?public ResponseResult login(User user) {

? ? ? ?UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(user.getUserName(),user.getPassword());

? ? ? ?Authentication authenticate = authenticationManager.authenticate(authenticationToken);

? ? ? ?if(Objects.isNull(authenticate)){

? ? ? ? ? ?throw new RuntimeException("用戶名或密碼錯誤");

? ? ? }

? ? ? ?//使用userid生成token

? ? ? ?LoginUser loginUser = (LoginUser) authenticate.getPrincipal();

? ? ? ?String userId = loginUser.getUser().getId().toString();

? ? ? ?String jwt = JwtUtil.createJWT(userId);

? ? ? ?//authenticate存入redis

? ? ? ?redisCache.setCacheObject("login:"+userId,loginUser);

? ? ? ?//把token響應(yīng)給前端

? ? ? ?HashMap map = new HashMap<>();

? ? ? ?map.put("token",jwt);

? ? ? ?return new ResponseResult(200,"登陸成功",map);

? }

}

HttpServletRequest request =new HttpSerletRequest();

String token = request.getHeader("token");

獲取Http請求頭中的token,解析獲取用戶ID

Clamis clamis = null;

userId = claims.getSubject();

token超時或非法就重新登錄。

去redis中找用戶,存入securityContextHolder中

放行,doFilter(自定義過濾器)

獲取userId生成token

JwtUtil.creatJwt(userId);

?

import io.jsonwebtoken.Claims;

import io.jsonwebtoken.JwtBuilder;

import io.jsonwebtoken.Jwts;

import io.jsonwebtoken.SignatureAlgorithm;

?

import javax.crypto.SecretKey;

import javax.crypto.spec.SecretKeySpec;

import java.util.Base64;

import java.util.Date;

import java.util.UUID;

?

/**

* JWT工具類

*/

public class JwtUtil {

?

? ?//有效期為

? ?public static final Long JWT_TTL = 60 * 60 *1000L;// 60 * 60 *1000 一個小時

? ?//設(shè)置秘鑰明文

? ?public static final String JWT_KEY = "Haluki";

?

? ?public static String getUUID(){

? ? ? ?String token = UUID.randomUUID().toString().replaceAll("-", "");

? ? ? ?return token;

? }

? ?

? ?/**

? ? * 生成jtw

? ? * @param subject token中要存放的數(shù)據(jù)(json格式)

? ? * @return

? ? */

? ?public static String createJWT(String subject) {

? ? ? ?JwtBuilder builder = getJwtBuilder(subject, null, getUUID());// 設(shè)置過期時間

? ? ? ?return builder.compact();

? }

?

? ?/**

? ? * 生成jtw

? ? * @param subject token中要存放的數(shù)據(jù)(json格式)

? ? * @param ttlMillis token超時時間

? ? * @return

? ? */

? ?public static String createJWT(String subject, Long ttlMillis) {

? ? ? ?JwtBuilder builder = getJwtBuilder(subject, ttlMillis, getUUID());// 設(shè)置過期時間

? ? ? ?return builder.compact();

? }

?

? ?private static JwtBuilder getJwtBuilder(String subject, Long ttlMillis, String uuid) {

? ? ? ?SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;

? ? ? ?SecretKey secretKey = generalKey();

? ? ? ?long nowMillis = System.currentTimeMillis();

? ? ? ?Date now = new Date(nowMillis);

? ? ? ?if(ttlMillis==null){

? ? ? ? ? ?ttlMillis=JwtUtil.JWT_TTL;

? ? ? }

? ? ? ?long expMillis = nowMillis + ttlMillis;

? ? ? ?Date expDate = new Date(expMillis);

? ? ? ?return Jwts.builder()

? ? ? ? ? ? ? .setId(uuid) ? ? ? ? ? ? ?//唯一的ID

? ? ? ? ? ? ? .setSubject(subject) ? // 主題 可以是JSON數(shù)據(jù)

? ? ? ? ? ? ? .setIssuer("haluki") ? ? // 簽發(fā)者

? ? ? ? ? ? ? .setIssuedAt(now) ? ? ?// 簽發(fā)時間

? ? ? ? ? ? ? .signWith(signatureAlgorithm, secretKey) //使用HS256對稱加密算法簽名, 第二個參數(shù)為秘鑰

? ? ? ? ? ? ? .setExpiration(expDate);

? }

?

? ?/**

? ? * 創(chuàng)建token

? ? * @param id

? ? * @param subject

? ? * @param ttlMillis

? ? * @return

? ? */

? ?public static String createJWT(String id, String subject, Long ttlMillis) {

? ? ? ?JwtBuilder builder = getJwtBuilder(subject, ttlMillis, id);// 設(shè)置過期時間

? ? ? ?return builder.compact();

? }

?

? ?public static void main(String[] args) throws Exception {

? ? ? ?String token = "eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiJjYWM2ZDVhZi1mNjVlLTQ0MDAtYjcxMi0zYWEwOGIyOTIwYjQiLCJzdWIiOiJzZyIsImlzcyI6InNnIiwiaWF0IjoxNjM4MTA2NzEyLCJleHAiOjE2MzgxMTAzMTJ9.JVsSbkP94wuczb4QryQbAke3ysBDIL5ou8fWsbt_ebg";

? ? ? ?Claims claims = parseJWT(token);

? ? ? ?System.out.println(claims);

? }

?

? ?/**

? ? * 生成加密后的秘鑰 secretKey

? ? * @return

? ? */

? ?public static SecretKey generalKey() {

? ? ? ?byte[] encodedKey = Base64.getDecoder().decode(JwtUtil.JWT_KEY);

? ? ? ?SecretKey key = new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");

? ? ? ?return key;

? }

? ?

? ?/**

? ? * 解析

? ? *

? ? * @param jwt

? ? * @return

? ? * @throws Exception

? ? */

? ?public static Claims parseJWT(String jwt) throws Exception {

? ? ? ?SecretKey secretKey = generalKey();

? ? ? ?return Jwts.parser()

? ? ? ? ? ? ? .setSigningKey(secretKey)

? ? ? ? ? ? ? .parseClaimsJws(jwt)

? ? ? ? ? ? ? .getBody();

? }

?

?

}

jwt是什么

JSON Web Token,目前最流行的跨域身份驗(yàn)證解決方案

為什么使用jwt

jwt的精髓在于去中心化,數(shù)據(jù)保存在客戶端里面。

jwt工作原理

在服務(wù)器身份驗(yàn)證后,生成一個JSON對象,并將其發(fā)回給用戶,之后,用戶與服務(wù)器通信時,用戶在請求中發(fā)回JSON對象,服務(wù)器將在生成對象時添加簽名。

jwt組成

頭部header、載荷payload、簽名signature。

文章訪問量沒必要用redis

博客主頁中的文章訪問量采用了redis技術(shù),為了更新的更加快速,減少查詢數(shù)據(jù)庫的次數(shù),減小數(shù)據(jù)庫壓力。但后來發(fā)現(xiàn)沒有必要,于是在博客后臺中圖表顯示瀏覽量就直接查詢數(shù)據(jù)庫了。

我使用了@Scheduled(cron = "0/5 * * * * ?")這個注解,每五秒種在redis中查詢一次瀏覽量數(shù)據(jù),使用stream流收集數(shù)據(jù),然后更新到數(shù)據(jù)庫中。

后臺中,文章某個時間段的瀏覽量

在設(shè)計方面,我使用文章id+每隔5分鐘的時間戳作為組合主鍵,用戶訪問文章時,以當(dāng)前時間上下5分鐘取整記錄到數(shù)據(jù)庫中。如果訪問量大就設(shè)計成時間戳%5min+文章Id+Count的方式記錄訪問量,計數(shù)的顆粒度是5分鐘,減小數(shù)據(jù)庫壓力,后臺可以查看任意時間段內(nèi)的文章瀏覽量。(顆粒度:數(shù)據(jù)的細(xì)化程度)

密碼加密算法

這個項(xiàng)目中,我使用了BCrypt加密算法對用戶密碼進(jìn)行加密處理。

為什么使用這個BC算法呢:這個算法對于攻擊人員來說需要消耗的計算成本高,安全性好。該算法會自動生成隨機(jī)鹽值??蓴U(kuò)展性高。適用于長密碼。簡單易用。 為什么不用最新的Argon2加密算法呢:Argon2加密算法很新,可能會導(dǎo)致不兼容的情況出現(xiàn),并且Argon2算法的計算成本高,高負(fù)載下可能產(chǎn)生性能問題。

密碼加密流程

pom

groupId:org.springframework.security

artifactId:spring-security-crypto

version:5.6.1

在配置文件中注入BCryptPasswordEncoder:

@Configuration

public class SecurityConfig extends WebSecurityConfigurerAdapter{

? ?@Bean

?public PasswordEncoder passwordEncoder(){

? ? ?return new BCryptPasswordEncoder();

}

}

在需要使用密碼的地方調(diào)用passwordEncoder.encode()方法對密碼進(jìn)行加密

@Autowired

private PasswordEncoder passwordEncoder;

@Override public User register(User user){

? ?String encodedPassword = passwordEncoder.encode(user.getPassword());

user.setPassword(encodedPassword);

?//...

return user;

}

圖片上傳

使用七牛云OSS存儲上傳的圖片,前端發(fā)起post請求,后端接收后處理上傳。

先添加七牛云的依賴,在配置文件里面輸入密鑰和私鑰以及bucket。后端響應(yīng)是否上傳成功,以及圖片的訪問鏈接

@SpringBootTest

@ConfigurationProperties(prefix = "oss")

public class OSSTest {

?

? ?private String accessKey;

? ?private String secretKey;

? ?private String bucket;

?

? ?public void setAccessKey(String accessKey) {

? ? ? ?this.accessKey = accessKey;

? }

?

? ?public void setSecretKey(String secretKey) {

? ? ? ?this.secretKey = secretKey;

? }

?

? ?public void setBucket(String bucket) {

? ? ? ?this.bucket = bucket;

? }

?

? ?@Test

? ?public void testOss(){

? ? ? ?//構(gòu)造一個帶指定 Region 對象的配置類

? ? ? ?Configuration cfg = new Configuration(Region.autoRegion());

? ? ? ?//...其他參數(shù)參考類注釋

?

? ? ? ?UploadManager uploadManager = new UploadManager(cfg);

? ? ? ?//...生成上傳憑證,然后準(zhǔn)備上傳

// ? ? ? String accessKey = "your access key";

// ? ? ? String secretKey = "your secret key";

// ? ? ? String bucket = "haluki";

?

? ? ? ?//默認(rèn)不指定key的情況下,以文件內(nèi)容的hash值作為文件名

? ? ? ?String key = "2022/xxx.png";

?

? ? ? ?try {

// ? ? ? ? ? byte[] uploadBytes = "hello qiniu cloud".getBytes("utf-8");

// ? ? ? ? ? ByteArrayInputStream byteInputStream=new ByteArrayInputStream(uploadBytes);

?

?

? ? ? ? ? ?InputStream inputStream = new FileInputStream("C:\\Users\\root\\Desktop\\Snipaste_2022-02-28_22-48-37.png");

? ? ? ? ? ?Auth auth = Auth.create(accessKey, secretKey);

? ? ? ? ? ?String upToken = auth.uploadToken(bucket);

?

? ? ? ? ? ?try {

? ? ? ? ? ? ? ?Response response = uploadManager.put(inputStream,key,upToken,null, null);

? ? ? ? ? ? ? ?//解析上傳成功的結(jié)果

? ? ? ? ? ? ? ?DefaultPutRet putRet = new Gson().fromJson(response.bodyString(), DefaultPutRet.class);

? ? ? ? ? ? ? ?System.out.println(putRet.key);

? ? ? ? ? ? ? ?System.out.println(putRet.hash);

? ? ? ? ? } catch (QiniuException ex) {

? ? ? ? ? ? ? ?Response r = ex.response;

? ? ? ? ? ? ? ?System.err.println(r.toString());

? ? ? ? ? ? ? ?try {

? ? ? ? ? ? ? ? ? ?System.err.println(r.bodyString());

? ? ? ? ? ? ? } catch (QiniuException ex2) {

? ? ? ? ? ? ? ? ? ?//ignore

? ? ? ? ? ? ? }

? ? ? ? ? }

? ? ? } catch (Exception ex) {

? ? ? ? ? ?//ignore

? ? ? }

?

? }

}

JPA

Java持久層API,將實(shí)體對象持久化到數(shù)據(jù)庫中。

博客

前后端分離。單賬戶,一個人發(fā)布博客,其他人可以登錄評論,可改頭像和個人信息,可評論??梢陨蟼饔焰湥@些用戶上傳的友鏈和發(fā)表的評論需要在后臺審核通過后才可以正常的上傳成功,后臺管理員可以對其修改或者刪除。

安全部分

設(shè)置允許跨域的路徑,請求方式,允許時間,cookie是否允許等。

安全部分主要是避免XSS和CSRF攻擊

XSS跨站腳本攻擊即用戶在輸入框內(nèi)輸入JavaScript代碼,此項(xiàng)目使用secure-only方式,只允許Https請求讀取發(fā)送請求時自動發(fā)送cookie

CSRF:登錄生成token為JSON對象,再返回給前端,之后每次客戶端與服務(wù)器交互的時候都會帶著token,服務(wù)器獲取用戶token解析獲取userId,在redis中找,再把這兩個token對比。

如何防止跨站請求偽造CSRF攻擊

SpringSecurity去防止CSRF攻擊的方式就是通過csrf_token。后端會生成一個csrf_token,前端發(fā)起請求的時候需要攜帶這個csrf_token,后端會有過濾器進(jìn)行校驗(yàn),如果沒有攜帶或者是偽造的就不允許訪問。SpringSecurity默認(rèn)啟用了CSRF防護(hù),要禁用CSRF防護(hù),可以在configure()方法中配置HttpSecurity:

@Configuration

@EnableWebSecurity

public class SecurityConfig extends WebSecurityConfigurerAdapter{

?

?@Override

?protected void configure(HttpSecurity http)throws Exception{

? ?http.csrf().disable()

? ? .authorizeRequests()

? ? .antMatchers("/admin/**").hasRole("ADMIN")

? ? .antMatchers("/user/**").hasRole("USER")

? ? .anyRequest().authenticated()

? ? .and()

? ? .formLogin()

? ? .and()

? ? .httpBasic();

}

}

如何在SpringSecurity中自定義認(rèn)證邏輯

需要實(shí)現(xiàn)AuthenticationProvider接口,并在configure() 方法中將自定義的AuthenticationProvider添加到AuthenticationManagerBuilder。

@Configuration

@EnableWebSecurity

public class SecurityConfig extends WebSecurityConfigurerAdapter{

? ?@Autowired

?private CutomAuthenticationProvider provider;

?

?@Override

?protected void configure(AuthenticationManagerBuilder auth){

? ?auth.authenticationProvider(provider);

}

}

如何在SpringSecurity中使用基于角色的控制訪問

所以我們在項(xiàng)目中只需要把當(dāng)前登錄用戶的權(quán)限信息也存入Authentication。

? 然后設(shè)置我們的資源所需要的權(quán)限即可。

SpringSecurity為我們提供了基于注解的權(quán)限控制方案,這也是我們項(xiàng)目中主要采用的方式。我們可以使用注解去指定訪問對應(yīng)的資源所需的權(quán)限。

? 但是要使用它我們需要先開啟相關(guān)配置。

@EnableGlobalMethodSecurity(prePostEnabled = true)

? 然后就可以使用對應(yīng)的注解。@PreAuthorize

@RestController

public class HelloController {

?

? ?@RequestMapping("/hello")

? ?@PreAuthorize("hasAuthority('test')")

? ?public String hello(){

? ? ? ?return "hello";

? }

}

可以在configure()中配置HttpSecurity

@Configuration

@EnableWebSecurity

public class SecurityConfig extends WebSecurityConfigurerAdapter{

?

?@Override

?protected void configure(HttpSecurity http)throws Exception{

? ?http.authorizeRequests()

? ? .antMatchers("/admin/**").hasRole("ADMIN")

? ? .antMatchers("/user/**").hasRole("USER")

? ? .anyRequest().authenticated()

? ? .and()

? ? .formLogin()

? ? .and()

? ? .httpBasic();

}

}

自定義jwt認(rèn)證過濾器

這個過濾器會去獲取請求頭中的token,對token進(jìn)行解析取出其中的userid。

? 使用userid去redis中獲取對應(yīng)的LoginUser對象。

? 然后封裝Authentication對象存入SecurityContextHolder

把jwtAuthenticationTokenFilter添加到SpringSecurity的過濾器鏈中

? http.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);

? //允許跨域

? http.cors();

@Component

public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {

?

? ?@Autowired

? ?private RedisCache redisCache;

?

? ?@Override

? ?protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {

? ? ? ?//獲取token

? ? ? ?String token = request.getHeader("token");

? ? ? ?if (!StringUtils.hasText(token)) {

? ? ? ? ? ?//放行

? ? ? ? ? ?filterChain.doFilter(request, response);

? ? ? ? ? ?return;

? ? ? }

? ? ? ?//解析token

? ? ? ?String userid;

? ? ? ?try {

? ? ? ? ? ?Claims claims = JwtUtil.parseJWT(token);

? ? ? ? ? ?userid = claims.getSubject();

? ? ? } catch (Exception e) {

? ? ? ? ? ?e.printStackTrace();

? ? ? ? ? ?throw new RuntimeException("token非法");

? ? ? }

? ? ? ?//從redis中獲取用戶信息

? ? ? ?String redisKey = "login:" + userid;

? ? ? ?LoginUser loginUser = redisCache.getCacheObject(redisKey);

? ? ? ?if(Objects.isNull(loginUser)){

? ? ? ? ? ?throw new RuntimeException("用戶未登錄");

? ? ? }

? ? ? ?//存入SecurityContextHolder

? ? ? ?//TODO 獲取權(quán)限信息封裝到Authentication中

? ? ? ?UsernamePasswordAuthenticationToken authenticationToken =

? ? ? ? ? ? ? ?new UsernamePasswordAuthenticationToken(loginUser,null,null);

? ? ? ?SecurityContextHolder.getContext().setAuthentication(authenticationToken);

? ? ? ?//放行

? ? ? ?filterChain.doFilter(request, response);

? }

}

自定義認(rèn)證成功處理器

自定義認(rèn)證失敗處理

如果是認(rèn)證過程中出現(xiàn)的異常會被封裝成AuthenticationException然后調(diào)用AuthenticationEntryPoint對象的方法去進(jìn)行異常處理。

? 如果是授權(quán)過程中出現(xiàn)的異常會被封裝成AccessDeniedException然后調(diào)用AccessDeniedHandler對象的方法去進(jìn)行異常處理。

所以,如果我們需要自定義異常處理,我們只需要自定義AuthenticationEntryPoint和AccessDeniedHandler然后配置給SpringSecurity即可

自定義實(shí)現(xiàn)類

@Component

public class AccessDeniedHandlerImpl implements AccessDeniedHandler {

? ?@Override

? ?public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {

? ? ? ?ResponseResult result = new ResponseResult(HttpStatus.FORBIDDEN.value(), "權(quán)限不足");

? ? ? ?String json = JSON.toJSONString(result);

? ? ? ?WebUtils.renderString(response,json);

?

? }

}

@Component

public class AuthenticationEntryPointImpl implements AuthenticationEntryPoint {

? ?@Override

? ?public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {

? ? ? ?ResponseResult result = new ResponseResult(HttpStatus.UNAUTHORIZED.value(), "認(rèn)證失敗請重新登錄");

? ? ? ?String json = JSON.toJSONString(result);

? ? ? ?WebUtils.renderString(response,json);

? }

}

配置給SpringSecurity

先注入對應(yīng)的處理器

@Autowired

private AuthenticationEntryPoint authenticationEntryPoint;

?

@Autowired

private AccessDeniedHandler accessDeniedHandler;

然后我們可以使用HttpSecurity對象的方法去配置

http.exceptionHandling().authenticationEntryPoint(autheticationEntryPoint).accessDeniedHandler(accessDeniedHandler);

如何在springSecurity中實(shí)現(xiàn)jwt認(rèn)證

首先引入依賴:jjwt 實(shí)現(xiàn)一個用于生成和解析jwt的工具類 創(chuàng)建自定義的AuthenticationFilter,用于從請求頭中提取jwt并進(jìn)行認(rèn)證。 在securityConfig類中配置HttpSecurity,將自定義的AuthenticationFilter添加到過濾鏈 @Configuration

@EnableWebSecurity

public class SecurityConfig extends WebSecurityConfigurerAdapter{

?

?@Autowired

?private JwtAuthenticationFilter jwtAuFilter;

?

?@Override

?protected void configure(HttpSecurity http)throws Exception{

? ?http.csrf().disable()

? ? .sessionManagement()

? ? .sessionCreationPolicy(SessionCreationPolicy.STATELESS)

? ? .and()

? ? .addFilterBefore(jwtAuFilter,usernamePasswordAuthentication.class)

? ? .anyRequest().authenticated();

? ?//把token校驗(yàn)過濾器添加到過濾器鏈中

? ? ? ?http.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);

}

}

在上述代碼中,禁用了CSRF防護(hù)和會話管理,然后將自定義的JwtAuthenticationFilter添加到過濾器鏈。

認(rèn)證成功的話要生成一個jwt,放入響應(yīng)中返回。并且為了讓用戶下回請求時能通過jwt識別出具體的是哪個用戶,我們需要把用戶信息存入redis,可以把用戶id作為key,最后把token響應(yīng)給前端。

@Service

public class LoginServiceImpl implements LoginServcie {

?

? ?@Autowired

? ?private AuthenticationManager authenticationManager;

? ?@Autowired

? ?private RedisCache redisCache;

?

? ?@Override

? ?public ResponseResult login(User user) {

? ? ? ?UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(user.getUserName(),user.getPassword());

? ? ? ?Authentication authenticate = authenticationManager.authenticate(authenticationToken);

? ? ? ?if(Objects.isNull(authenticate)){

? ? ? ? ? ?throw new RuntimeException("用戶名或密碼錯誤");

? ? ? }

? ? ? ?//使用userid生成token

? ? ? ?LoginUser loginUser = (LoginUser) authenticate.getPrincipal();

? ? ? ?String userId = loginUser.getUser().getId().toString();

? ? ? ?String jwt = JwtUtil.createJWT(userId);

? ? ? ?//authenticate存入redis

? ? ? ?redisCache.setCacheObject("login:"+userId,loginUser);

? ? ? ?//把token響應(yīng)給前端

? ? ? ?HashMap map = new HashMap<>();

? ? ? ?map.put("token",jwt);

? ? ? ?return new ResponseResult(200,"登陸成功",map);

? }

}

得物項(xiàng)目

Redis給鍵值加過期時間

減少redis空間占用以防止用戶惡意查詢,在得物項(xiàng)目中使用的是定時刪除

Redis三大刪除策略

定時刪除:設(shè)置過期時間 惰性刪除:每次從數(shù)據(jù)庫中取鍵值時判斷是否過期 定期刪除:每隔一段時間查一次數(shù)據(jù)庫,可以在redis.config文件中配置,隨機(jī)刪除過期鍵

分布式鎖

為了確保分布式鎖可用,至少要確保鎖的實(shí)現(xiàn)同時滿足以下四個條件:

互斥性。在任意時刻,只有一個客戶端能持有鎖。 不會發(fā)生死鎖。即使有一個客戶端在持有鎖的期間崩潰而沒有主動解鎖,也能保證后續(xù)其他客戶端能加鎖。 加鎖和解鎖必須是同一個客戶端,客戶端自己不能把別人加的鎖解開,不能誤解鎖。 具有容錯性。只要大多數(shù)Redis節(jié)點(diǎn)正常運(yùn)行,客戶端就能夠獲取和釋放鎖。

如何解決商品超賣

我使用了Redisson的分布式鎖組件

RLock rlock = redisson.getLock(key);

獲取到鎖->開啟事務(wù)->釋放鎖

// 1.構(gòu)造redisson實(shí)現(xiàn)分布式鎖必要的Config

Config config = new Config();

config.useSingleServer().setAddress("redis://127.0.0.1:5379").setPassword("123456").setDatabase(0);

// 2.構(gòu)造RedissonClient

RedissonClient redissonClient = Redisson.create(config);

// 3.獲取鎖對象實(shí)例(無法保證是按線程的順序獲取到)

RLock rLock = redissonClient.getLock(lockKey);

try {

? ?/**

? ? * 4.嘗試獲取鎖

? ? * waitTimeout 嘗試獲取鎖的最大等待時間,超過這個值,則認(rèn)為獲取鎖失敗

? ? * leaseTime ? 鎖的持有時間,超過這個時間鎖會自動失效(值應(yīng)設(shè)置為大于業(yè)務(wù)處理的時間,確保在鎖有效期內(nèi)業(yè)務(wù)能處理完)

? ? */

? ?boolean res = rLock.tryLock((long)waitTimeout, (long)leaseTime, TimeUnit.SECONDS);

? ?if (res) {

? ? ? ?//成功獲得鎖,在這里處理業(yè)務(wù)

? }

} catch (Exception e) {

? ?throw new RuntimeException("aquire lock fail");

}finally{

? ?//無論如何, 最后都要解鎖

? ?rLock.unlock();

}

Redis針對緩存穿透、擊穿、雪崩的解決方案

緩存穿透:存在則緩存返回,不存在則查詢db,惡意查詢不存在的key對后端壓力增大就叫穿透 解決方案:查詢?yōu)榭盏臅r候緩存下(緩存空值,并設(shè)置過期時間),查詢以后更新緩存,過濾key 緩存擊穿:緩存中沒有但數(shù)據(jù)庫中也可能沒有,大量查詢穿過緩存直擊數(shù)據(jù)庫 解決方案:使用互斥鎖,當(dāng)1號線程查詢緩存未命中時,去獲取互斥鎖,然后查詢數(shù)據(jù)庫獲取結(jié)果并將結(jié)果寫入到緩存中,最后釋放鎖,在1號線程釋放鎖之前,其他線程都不能獲取到鎖,只能睡眠一段時間后重試,如果能命中緩存,則返回數(shù)據(jù),否則繼續(xù)嘗試獲取互斥鎖 緩存雪崩:緩存服務(wù)器重啟或者大量緩存失效,都去訪問數(shù)據(jù)庫,引起數(shù)據(jù)庫壓力過大 解決方案:將key的過期時間分布均勻,避免短時間內(nèi)大量key過期,加鎖避免過大并發(fā)量,控制訪問流量。

訂單支付模塊

用戶下單付款 客戶端請求服務(wù)器獲取簽名后的訂單信息。 返回簽名后的訂單信息 調(diào)用支付接口,發(fā)送支付請求 返回支付結(jié)果 返回給服務(wù)器驗(yàn)證簽名,解析支付結(jié)果 返回最終支付結(jié)果 顯示支付結(jié)果

調(diào)用支付寶SDK,實(shí)例化客戶端

new DefaultAliPayClient("網(wǎng)關(guān)地址",APPID,應(yīng)用公鑰,參數(shù)格式JSON,編碼格式UTF-8,支付寶公鑰,簽名方式,RSA2)

調(diào)用接口生成表單,把信息填進(jìn)去,orderID、金額等。下單成功后更新支付記錄,更新商品付款人數(shù),更新訂單狀態(tài)。

配置回調(diào)地址->調(diào)用支付接口->支付成功->跳轉(zhuǎn)到回調(diào)地址->判斷訂單狀態(tài)

狀態(tài)為已支付:更新訂單狀態(tài)->更新支付流水->更新付款人數(shù)

狀態(tài)為未支付:更新訂單狀態(tài)為未支付->更新支付流水為支付失敗

豆瓣項(xiàng)目

Redis支持

String:此類型是二進(jìn)制安全的,可包含任何數(shù)據(jù),如jpg圖片或序列化的對象

Hash:是一個鍵值對集合,適合用于存儲對象

List:字符串列表,可在頭部(左邊)或尾部(右邊)插入數(shù)據(jù)

Set:是String類型的無序集合

ZSet:同Set,并且不允許重復(fù)成員

Mongodb與Mysql的區(qū)別

Mongodb本質(zhì)上還是一個數(shù)據(jù)庫產(chǎn)品,與MySQL的區(qū)別在于它不會遵循一些約束,比如sql標(biāo)準(zhǔn)、表結(jié)構(gòu)等

Mongodb特性

面向集合文檔的存儲,適合存儲Bson(JSON的擴(kuò)展)形式的數(shù)據(jù) 格式自由 強(qiáng)大的查詢語句 完整的索引支持 支持二進(jìn)制數(shù)據(jù)以及大型對象(文件)的高效存儲

爬蟲是如何實(shí)現(xiàn)的

構(gòu)建請求頭,不同的爬取目標(biāo)有不同的值。

String getContent(String url,Mapheaders){

? ?//定義request

Builder reqBuilder = new Request.Builder().url(url);

//如果傳入httpheader,則放入request中

if(headers!=null && !headers.isEmpty()){

? ? ? ?for(String key:headers.Keyset()){

? ? ? ? ?reqBuilder.addHeader(key,headers.get(key));

}

? }

?Request request ?= reqBuilder.build();

?//調(diào)用client去請求

?Call call = okHttpClient.newCall(reqeust);

?//返回結(jié)果字符串

?String result = null;

?try{

? ? ?//獲得返回結(jié)果

? logger.info("Requst" + url+ "Begin.");

? result = call.execute().body().string();

}catch(IOException e){

? ? ?logger.error("request"+url+"exception"+e);

}

?return result;

}

獲取數(shù)據(jù)后,轉(zhuǎn)換成Map格式

Map dataObj = JSON.parseObject(content,Map.class);

解析獲取到的數(shù)據(jù)

Map songListData = (Map)dataObj.get("songlist");

柚子快報激活碼778899分享:java 簡歷項(xiàng)目知識,八股文

http://yzkb.51969.com/

推薦閱讀

評論可見,查看隱藏內(nèi)容

本文內(nèi)容根據(jù)網(wǎng)絡(luò)資料整理,出于傳遞更多信息之目的,不代表金鑰匙跨境贊同其觀點(diǎn)和立場。

轉(zhuǎn)載請注明,如有侵權(quán),聯(lián)系刪除。

本文鏈接:http://gantiao.com.cn/post/19547781.html

發(fā)布評論

您暫未設(shè)置收款碼

請?jiān)谥黝}配置——文章設(shè)置里上傳

掃描二維碼手機(jī)訪問

文章目錄