日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Cloud E随笔-后端_piece3--实现登录功能

發(fā)布時(shí)間:2023/12/16 编程问答 46 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Cloud E随笔-后端_piece3--实现登录功能 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

目錄

  • 一、spring security 簡介
    • 1. 概要
    • 2. Spring Security 的核心功能
    • 3. Spring Security特點(diǎn)
  • 二、 登錄功能實(shí)現(xiàn)
    • 1. 添加pom依賴
    • 2. 修改配置文件 -application.yml
    • 3. 創(chuàng)建工具類
      • 3.1 新建JWTToken工具類
      • 3.2 Admin實(shí)現(xiàn)UserDetails類
      • 3.3 添加公共返回對象
      • 3.4 添加登錄相關(guān)對象AdminLoginParam
    • 4. 登錄功能實(shí)現(xiàn)
      • 4.1 LoginController編寫
      • 4.2 IAdminService接口編寫
      • 4.3 AdminServerImpl接口類的實(shí)現(xiàn)
    • 5. Security配置
      • 5.1 準(zhǔn)備配置類
      • 5.2 添加jwt 登錄授權(quán)攔截器
      • 5.3 添加自定義未授權(quán)未登錄結(jié)果返回
  • 三、 接口文檔Swagger2準(zhǔn)備
    • 1. 依賴添加
    • 2. Swagger2配置
    • 3. 登錄驗(yàn)證
    • 4. 添加驗(yàn)證碼模塊
      • 4.1 添加驗(yàn)證碼依賴
      • 4.2 添加驗(yàn)證碼配置文件
      • 4.3 驗(yàn)證碼生成
      • 4.4 修改登錄傳遞參數(shù)
    • 5. 登錄成功

一、spring security 簡介

1. 概要

Spring Security是Spring家族中的一員,Security基于Spring框架,提供了一套Web應(yīng)用安全性的完整解決方案。

2. Spring Security 的核心功能

主要包括:

  • 認(rèn)證 (你是誰)
  • 授權(quán) (你能干什么)
  • 攻擊防護(hù) (防止偽造身份)

其核心就是一組過濾器鏈,項(xiàng)目啟動(dòng)后將會(huì)自動(dòng)配置。最核心的就是 Basic Authentication Filter 用來認(rèn)證用戶的身份,一個(gè)在spring security中一種過濾器處理一種認(rèn)證方式。

3. Spring Security特點(diǎn)

  • 和 Spring 無縫整合。
  • 全面的權(quán)限控制。
  • 專門為 Web 開發(fā)而設(shè)計(jì)。
  • 舊版本不能脫離 Web 環(huán)境使用。
  • 新版本對整個(gè)框架進(jìn)行了分層抽取,分成了核心模塊和 Web 模塊。單獨(dú)引入核心模塊就可以脫離 Web 環(huán)境。
  • 重量級(缺點(diǎn))。

二、 登錄功能實(shí)現(xiàn)

項(xiàng)目中使用 Spring Security 框架實(shí)現(xiàn)登錄功能

1. 添加pom依賴

<!--security 依賴--> <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId> </dependency> <!--JWT 依賴--> <dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt</artifactId><version>0.9.1</version> </dependency>

2. 修改配置文件 -application.yml

# jwt配置 jwt:# JWT存儲的請求頭tokenHeader: Authorization# JWT 加解密使用的密鑰secret: cloude-secret# JWT的超期限時(shí)間(60*60*24)expiration: 604800# JWT 負(fù)載中拿到開頭tokenHead: Bearer

3. 創(chuàng)建工具類

3.1 新建JWTToken工具類

創(chuàng)建config.security目錄,并且在其目錄新建JwtTokenUtil.java文件

package com.chuci.server.config.security;import io.jsonwebtoken.Claims; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SignatureAlgorithm; import org.springframework.beans.factory.annotation.Value; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.stereotype.Component;import java.util.Date; import java.util.HashMap; import java.util.Map;/*** @Auther chuci* @Data 2021-12-22 22:43* @Description:*/ @Component public class JwtTokenUtil {private static final String CLAIM_KEY_USERNAME = "sub"; //荷載 用戶名private static final String CLAIM_KEY_CREATED = "created"; //荷載 創(chuàng)建時(shí)間// 通過配置獲取@Value("${jwt.secret}")private String secret; //JWT密鑰@Value("${jwt.expiration}")private Long expiration; //JWT失效時(shí)間/*** 根據(jù)用戶信息生成token* @param userDetails* @return*/public String generateToken(UserDetails userDetails){Map<String, Object> claims = new HashMap<>();claims.put(CLAIM_KEY_USERNAME, userDetails.getUsername());claims.put(CLAIM_KEY_CREATED, new Date());return generateToken(claims);}/*** 從token中獲取用戶名* @param token* @return*/public String getUserNameFromToken(String token){String username;try {Claims claims = getClaimsFromToken(token); //根據(jù)token獲取荷載username = claims.getSubject();}catch (Exception e){username = null;e.printStackTrace();}return username;}/*** 判斷token是否有效* @param token* @param userDetails* @return*/public boolean validateToken(String token, UserDetails userDetails){String username = getUserNameFromToken(token); // 判斷username是否一致以及token是否失效return username.equals(userDetails.getUsername()) && !isTokenExpired(token);}/*** 驗(yàn)證token是否可以被刷新* @param token* @return*/public boolean canRefresh(String token){return !isTokenExpired(token); //token過期就可以被刷新了}/*** 刷新token* @param token* @return*/public String refreshToken(String token){Claims claims = getClaimsFromToken(token);claims.put(CLAIM_KEY_CREATED, new Date()); //更新創(chuàng)建時(shí)間 達(dá)到刷新token的目的return generateToken(claims);}/*** 判斷token是否失效* @param token* @return*/private boolean isTokenExpired(String token) {Date expiredDate = getExpiredDateFromToken(token);return expiredDate.before(new Date());}/*** 從token中獲取時(shí)間* @param token* @return*/private Date getExpiredDateFromToken(String token) {Claims claims = getClaimsFromToken(token);return claims.getExpiration();}/*** 從token中獲取荷載* @param token* @return*/private Claims getClaimsFromToken(String token) {Claims claims = null;try {claims = Jwts.parser() //轉(zhuǎn)荷載.setSigningKey(secret) //添加簽名.parseClaimsJws(token) //添加密鑰.getBody(); //拿到荷載}catch (Exception e){e.printStackTrace();}return claims;}/*** 根據(jù)JWT生成token 私有 只需public String generateToken調(diào)用* @param claims* @return*/private String generateToken(Map<String, Object> claims){return Jwts.builder() //jwts生成.setClaims(claims) //荷載.setExpiration(generateExporation()) //失效時(shí)間.signWith(SignatureAlgorithm.HS512, secret) //簽名.compact(); //密鑰}/*** 生成token失效時(shí)間* @return*/private Date generateExporation() { // 系統(tǒng)當(dāng)前時(shí)間 加失效時(shí)間return new Date(System.currentTimeMillis() + expiration * 1000);} }

3.2 Admin實(shí)現(xiàn)UserDetails類


實(shí)現(xiàn)UserDetails,重寫其方法,將所有返回類型改為 true,但注意isEnabled()方法是否啟用賬號,返回值返回Admin類中enable屬性值,因此isEnabled()方法返回值為enabled。

package com.chuci.server.entity;import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import java.io.Serializable; import java.util.Collection;import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.userdetails.UserDetails;/*** <p>* * </p>** @author chuci* @since 2021-12-22*/ @TableName("t_admin") @ApiModel(value = "Admin對象", description = "") public class Admin implements Serializable, UserDetails {private static final long serialVersionUID = 1L;@ApiModelProperty("id")@TableId(value = "id", type = IdType.AUTO)private Integer id;@ApiModelProperty("姓名")private String name;@ApiModelProperty("手機(jī)號碼")private String phone;@ApiModelProperty("住宅電話")private String telephone;@ApiModelProperty("聯(lián)系地址")private String address;@ApiModelProperty("是否啟用")private Boolean enabled;@ApiModelProperty("用戶名")private String username;@ApiModelProperty("密碼")private String password;@ApiModelProperty("用戶頭像")private String userFace;@ApiModelProperty("備注")private String remark;public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getPhone() {return phone;}public void setPhone(String phone) {this.phone = phone;}public String getTelephone() {return telephone;}public void setTelephone(String telephone) {this.telephone = telephone;}public String getAddress() {return address;}public void setAddress(String address) {this.address = address;}public Boolean getEnabled() {return enabled;}public void setEnabled(Boolean enabled) {this.enabled = enabled;}public String getUsername() {return username;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}public String getUserFace() {return userFace;}public void setUserFace(String userFace) {this.userFace = userFace;}public String getRemark() {return remark;}public void setRemark(String remark) {this.remark = remark;}/*** 重寫 實(shí)現(xiàn) UserDetails* @return*/@Overridepublic boolean isAccountNonExpired() {return true;}@Overridepublic boolean isAccountNonLocked() {return true;}@Overridepublic boolean isCredentialsNonExpired() {return true;}@Overridepublic boolean isEnabled() {return enabled; //是否啟用}public void setUsername(String username) {this.username = username;}@Overridepublic Collection<? extends GrantedAuthority> getAuthorities() {return null;}/*** 重寫toString* @return*/@Overridepublic String toString() {return "Admin{" +"id=" + id +", name=" + name +", phone=" + phone +", telephone=" + telephone +", address=" + address +", enabled=" + enabled +", username=" + username +", password=" + password +", userFace=" + userFace +", remark=" + remark +"}";} }

3.3 添加公共返回對象

每次請求,為了前后端參數(shù)統(tǒng)一,規(guī)定公共返回對象SysResult
創(chuàng)建vo目錄,并且新建SysResult.java。包含狀態(tài)碼code, 返回信息message以及返回對象data。并創(chuàng)建success方法以及error方法。同是使用lombok生成無參全參構(gòu)造方法以及get/set方法。
注:返回對象可返回任何對象類型。

package com.chuci.server.vo;import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor;/*** 公共返回對象** @Auther chuci* @Data 2022-01-09 22:26* @Description:*/ @Data @NoArgsConstructor @AllArgsConstructor public class SysResult {private long code; //狀態(tài)碼private String message; //返回信息private Object data; //返回對象/*** 請求成功返回對象* @return*/public static SysResult success(){return new SysResult(200, "服務(wù)請求成功", null);}public static SysResult success(String msg){return new SysResult(200, msg, null);}public static SysResult success(String msg, Object data){return new SysResult(200, msg, data);}/*** 請求失敗* @return*/public static SysResult error(){return new SysResult(500, "服務(wù)請求失敗", null);}public static SysResult error(String msg){return new SysResult(500, msg, null);}public static SysResult error(String msg, Object data){return new SysResult(500, msg, data);} }

3.4 添加登錄相關(guān)對象AdminLoginParam

創(chuàng)建目錄結(jié)構(gòu)bean,并且新建文件AdminLoginParam.java文件用來登錄時(shí)參數(shù)傳遞。若使用Admin實(shí)體進(jìn)行登錄實(shí)體對象,則傳遞的對象太大,所以在這里進(jìn)行簡化,暫時(shí)僅傳遞 用戶名以及密碼即可(后期還需要傳遞驗(yàn)證碼)。

package com.chuci.server.bean;import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor;/*** 用戶登錄實(shí)體類** @Auther chuci* @Data 2022-01-10 15:08* @Description:*/@Data @NoArgsConstructor @AllArgsConstructor @ApiModel(value = "AdminLogin實(shí)體類", description = "") public class AdminLoginParam {@ApiModelProperty(value = "用戶名", required = true)private String username;@ApiModelProperty(value = "密碼", required = true)private String password;}

4. 登錄功能實(shí)現(xiàn)

4.1 LoginController編寫

新建文件LoginController.java并進(jìn)行登錄代碼控制層的編寫,主要實(shí)現(xiàn):

  • 用戶登錄
  • 登錄用戶信息獲取
  • 退出登錄
  • package com.chuci.server.controller;import com.chuci.server.entity.Admin; import com.chuci.server.service.IAdminService; import com.chuci.server.bean.AdminLoginParam; import com.chuci.server.vo.SysResult; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController;import javax.servlet.http.HttpServletRequest; import java.security.Principal;/*** 登錄** @Auther chuci* @Data 2022-01-10 15:12* @Description:*/ @Api(tags = "LoginController") @RestController public class LoginController {@Autowiredprivate IAdminService adminService;/*** 進(jìn)行登錄操作,返回SysResult對象。data包含登錄所需驗(yàn)證* @param adminLoginParam* @param request* @return*/@ApiOperation(value = "登陸之后返回token")@PostMapping("/login")public SysResult login(@RequestBody AdminLoginParam adminLoginParam, HttpServletRequest request){return adminService.login(adminLoginParam.getUsername(), adminLoginParam.getPassword(), adminLoginParam.getCode(), request);}/*** 登錄成功,獲取當(dāng)前登錄對象所有信息* @param principal* @return*/@ApiOperation(value = "獲取當(dāng)前登錄用戶信息")@GetMapping("/admin/info")public Admin getAdminInfo(Principal principal){if (principal == null){return null;}String username = principal.getName();Admin admin = adminService.getAdminByUserName(username);admin.setPassword(null);return admin;}/*** 退出登錄,前端刪除token進(jìn)行退出操作* @return*/@ApiOperation(value = "退出登錄")@PostMapping("/logout")public SysResult logout(){return SysResult.success("注銷成功");}}

    4.2 IAdminService接口編寫

    由MybatisPlus代碼生成器生成的所有Service接口,前綴均有“I”標(biāo)注,即Admin實(shí)體的Service接口為IAdminService。
    主要實(shí)現(xiàn)登錄以及登錄用戶信息的查詢。

    public interface IAdminService extends IService<Admin> {/*** 登錄之后返回token** @param code* @param username* @param password* @param request* @return*/SysResult login(String username, String password, HttpServletRequest request);/*** 根據(jù)用戶名獲取用戶信息* @param username* @return*/Admin getAdminByUserName(String username); }

    4.3 AdminServerImpl接口類的實(shí)現(xiàn)

    package com.chuci.server.service.impl;import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.chuci.server.config.security.JwtTokenUtil; import com.chuci.server.entity.Admin; import com.chuci.server.mapper.AdminMapper; import com.chuci.server.service.IAdminService; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.chuci.server.vo.SysResult; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; import org.springframework.util.StringUtils;import javax.servlet.http.HttpServletRequest; import java.util.HashMap; import java.util.Map;/*** <p>* 服務(wù)實(shí)現(xiàn)類* </p>** @author chuci* @since 2021-12-22*/ @Service public class AdminServiceImpl extends ServiceImpl<AdminMapper, Admin> implements IAdminService {@Autowiredprivate UserDetailsService userDetailsService;@Autowiredprivate PasswordEncoder passwordEncoder;@Autowiredprivate JwtTokenUtil jwtTokenUtil;@Autowiredprivate AdminMapper adminMapper;@Value("${jwt.tokenHead}")private String tokenHead;/*** 登陸之后返回token** @param code* @param username* @param password* @param request* @return*/@Overridepublic SysResult login(String username, String password, String code, HttpServletRequest request) { // 登錄UserDetails userDetails = userDetailsService.loadUserByUsername(username);if (userDetails == null || passwordEncoder.matches(password,userDetails.getPassword())){return SysResult.error("用戶密碼不正確");}if(!userDetails.isEnabled()){return SysResult.error("賬號禁用,請聯(lián)系管理員!");}// 更新登錄用戶對象UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken =new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);// 生成tokenString token = jwtTokenUtil.generateToken(userDetails);Map<String, String> tokenMap = new HashMap<>();tokenMap.put("token", token);tokenMap.put("tokenHead", tokenHead);return SysResult.success("登錄成功", tokenMap);}/*** 根據(jù)用戶名獲取用戶信息* @param username* @return*/@Overridepublic Admin getAdminByUserName(String username) {return adminMapper.selectOne(new QueryWrapper<Admin>().eq("username", username).eq("enabled", true));} }

    5. Security配置

    5.1 準(zhǔn)備配置類

    新建文件 SecurityConfig.java
    SpringSecurity的登錄邏輯是通過UserDetailsService中的loadByUserName來實(shí)現(xiàn)的。重寫userDetailsService()方法并重新實(shí)現(xiàn)configure(AuthenticationManagerBuilder auth)。configure(WebSecurity web)開放部分接口以及資源。configure(HttpSecurity http)使用JWT, 不需要csrf。

    package com.chuci.server.config.security;import com.chuci.server.entity.Admin; import com.chuci.server.service.IAdminService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.builders.WebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;/*** @Auther chuci* @Data 2022-01-10 22:34* @Description: Security配置類*/ @Configuration public class SecurityConfig extends WebSecurityConfigurerAdapter {@Autowiredprivate IAdminService adminService;@Autowiredprivate RestfulAccessDeniedHandler restfulAccessDeniedHandler;@Autowiredprivate RestAuthorizationEntryPoint restAuthorizationEntryPoint;@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {auth.userDetailsService(userDetailsService()).passwordEncoder(passwordEncoder());}/*** 開放以下接口網(wǎng)頁資源不進(jìn)行安全認(rèn)證* @param web* @throws Exception*/@Overridepublic void configure(WebSecurity web) throws Exception {web.ignoring().antMatchers("/login","/logout","/captcha","css/**","js/**","/webjars/**","/swagger-resources/**","/v2/api-docs/**","/index.html","/doc.html","favicon.ico");}@Overrideprotected void configure(HttpSecurity http) throws Exception { // 使用JWT, 不需要csrfhttp.csrf().disable() // 基于token, 不需要session.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and().authorizeRequests() // 所有請求都需要認(rèn)證.anyRequest().authenticated().and().headers().cacheControl(); // 添加jwt 登錄授權(quán)攔截器http.addFilterBefore(jwtAuthencationTokenFilter(), UsernamePasswordAuthenticationFilter.class); // 添加自定義未授權(quán)未登錄結(jié)果返回http.exceptionHandling().accessDeniedHandler(restfulAccessDeniedHandler).authenticationEntryPoint(restAuthorizationEntryPoint);}@Override@Beanpublic UserDetailsService userDetailsService() {return username -> {Admin admin = adminService.getAdminByUserName(username);if (admin != null) {return admin;}return null;};}@Beanpublic PasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}@Beanpublic JWTAuthencationTokenFilter jwtAuthencationTokenFilter() {return new JWTAuthencationTokenFilter();} }

    5.2 添加jwt 登錄授權(quán)攔截器

    新建JWTAuthencationTokenFilter.java 文件

    package com.chuci.server.config.security;import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.web.authentication.WebAuthenticationDetailsSource; import org.springframework.web.filter.OncePerRequestFilter;import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException;/*** @Auther chuci* @Data 2022-01-10 22:59* @Description: JWT 登錄授權(quán)過濾器*/public class JWTAuthencationTokenFilter extends OncePerRequestFilter {@Value("${jwt.tokenHeader}")private String tokenHeader;@Value("${jwt.tokenHead}")private String tokenHead;@Autowiredprivate JwtTokenUtil jwtTokenUtil;@Autowiredprivate UserDetailsService userDetailsService;@Overrideprotected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {String authHeader = request.getHeader(tokenHeader); // 存在tokenif(authHeader != null && authHeader.startsWith(tokenHead)){String authToken = authHeader.substring(tokenHead.length());String username = jwtTokenUtil.getUserNameFromToken(authToken); // token存在用戶但未登錄if (username != null && SecurityContextHolder.getContext().getAuthentication() == null){UserDetails userDetails = userDetailsService.loadUserByUsername(username); // 驗(yàn)證token是否有效,重新設(shè)置用戶對象if (jwtTokenUtil.validateToken(authToken, userDetails)){UsernamePasswordAuthenticationToken authenticationToken =new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));SecurityContextHolder.getContext().setAuthentication(authenticationToken);}}}filterChain.doFilter(request, response);} }

    5.3 添加自定義未授權(quán)未登錄結(jié)果返回

  • 未授權(quán)結(jié)果返回
  • package com.chuci.server.config.security;import com.chuci.server.vo.SysResult; import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.security.access.AccessDeniedException; import org.springframework.security.web.access.AccessDeniedHandler; import org.springframework.stereotype.Component;import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.PrintWriter;/*** @Auther chuci* @Data 2022-01-14 22:06* @Description:*/@Component public class RestfulAccessDeniedHandler implements AccessDeniedHandler {@Overridepublic void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AccessDeniedException e) throws IOException, ServletException {httpServletResponse.setCharacterEncoding("UTF-8");httpServletResponse.setContentType("application/json");PrintWriter writer = httpServletResponse.getWriter();SysResult result = SysResult.error("權(quán)限不足,請聯(lián)系管理員");result.setCode(403);writer.write(new ObjectMapper().writeValueAsString(result));writer.flush();writer.close();} }
  • 未登錄結(jié)果返回
  • package com.chuci.server.config.security;import com.chuci.server.vo.SysResult; import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.security.core.AuthenticationException; import org.springframework.security.web.AuthenticationEntryPoint; import org.springframework.stereotype.Component;import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.PrintWriter;/*** @Auther chuci* @Data 2022-01-14 21:42* @Description:*/ @Component public class RestAuthorizationEntryPoint implements AuthenticationEntryPoint {@Overridepublic void commence(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {httpServletResponse.setCharacterEncoding("UTF-8"); //設(shè)置編碼格式httpServletResponse.setContentType("application/json"); //設(shè)置傳輸為JSON格式PrintWriter writer = httpServletResponse.getWriter();SysResult result = SysResult.error("尚未登錄,請登錄后再試!");result.setCode(401);writer.write(new ObjectMapper().writeValueAsString(result));writer.flush();writer.close();} }

    三、 接口文檔Swagger2準(zhǔn)備

    在團(tuán)隊(duì)開發(fā)中,一個(gè)好的 API 文檔不但可以減少大量的溝通成本,還可以幫助一位新人快速上手業(yè)務(wù)。傳統(tǒng)的做法是由開發(fā)人員創(chuàng)建一份 RESTful API 文檔來記錄所有的接口細(xì)節(jié),并在程序員之間代代相傳。

    這種做法存在以下幾個(gè)問題:

    • API 接口眾多,細(xì)節(jié)復(fù)雜,需要考慮不同的HTTP請求類型、HTTP頭部信息、HTTP請求內(nèi)容等,想要高質(zhì)量的完成這份文檔需要耗費(fèi)大量的精力;

    • 難以維護(hù)。隨著需求的變更和項(xiàng)目的優(yōu)化、推進(jìn),接口的細(xì)節(jié)在不斷地演變,接口描述文檔也需要同步修訂,可是文檔和代碼處于兩個(gè)不同的媒介,除非有嚴(yán)格的管理機(jī)制,否則很容易出現(xiàn)文檔、接口不一致的情況

    Swagger2 的出現(xiàn)就是為了從根本上解決上述問題。它作為一個(gè)規(guī)范和完整的框架,可以用于生成、描述、調(diào)用和可視化 RESTful 風(fēng)格的 Web 服務(wù):

  • 接口文檔在線自動(dòng)生成,文檔隨接口變動(dòng)實(shí)時(shí)更新,節(jié)省維護(hù)成本

  • 支持在線接口測試,不依賴第三方工具

  • 1. 依賴添加

    Swagger2自帶UI不太好看,之后更換第三方UI界面

    <!-- swagger2 依賴 --><dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger2</artifactId><version>2.9.2</version></dependency><!-- Swagger第三方ui依賴 --> <!-- 太丑了,顏色太亮--> <!-- <dependency>--> <!-- <groupId>com.github.xiaoymin</groupId>--> <!-- <artifactId>swagger-bootstrap-ui</artifactId>--> <!-- <version>1.9.6</version>--> <!-- </dependency>--><!--解決集成knife4j時(shí)沖突問題--><dependency><groupId>com.google.guava</groupId><artifactId>guava</artifactId><version>31.0.1-jre</version></dependency><dependency><groupId>com.github.xiaoymin</groupId><artifactId>knife4j-micro-spring-boot-starter</artifactId><version>2.0.5</version></dependency><dependency><groupId>com.github.xiaoymin</groupId><artifactId>knife4j-spring-boot-starter</artifactId><version>2.0.5</version></dependency>

    2. Swagger2配置

    在config文件夾下創(chuàng)建新文件夾swagger存放Swagger2配置類。新建SwaggerConfig.java文件

    在這里進(jìn)行簡單常用配置

    package com.chuci.server.config.swagger;import com.github.xiaoymin.knife4j.spring.annotations.EnableKnife4j; import org.checkerframework.checker.units.qual.A; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import springfox.documentation.builders.ApiInfoBuilder; import springfox.documentation.builders.PathSelectors; import springfox.documentation.builders.RequestHandlerSelectors; import springfox.documentation.service.*; import springfox.documentation.spi.DocumentationType; import springfox.documentation.spi.service.contexts.SecurityContext; import springfox.documentation.spring.web.plugins.Docket; import springfox.documentation.swagger2.annotations.EnableSwagger2;import java.util.ArrayList; import java.util.List;/*** @Auther chuci* @Data 2022-01-14 22:22* @Description:*/ @Configuration @EnableSwagger2 //啟用Swagger2 @EnableKnife4j //啟用Knife4j public class SwaggerConfig {/*** 通過@Configuration注解,讓Spring來加載該類配置。* 再通過@EnableSwagger2注解來啟用Swagger2。* <p>* 再通過createRestApi()函數(shù)創(chuàng)建Docket的Bean之后,* apiInfo()用來創(chuàng)建該Api的基本信息(這些基本信息會(huì)展現(xiàn)在文檔頁面中)。* select()函數(shù)返回一個(gè)ApiSelectorBuilder實(shí)例用來控制哪些接口暴露給Swagger來展現(xiàn)* 采用掃描所有定義,Swagger會(huì)掃描所有Controller定義的API,并產(chǎn)生文檔內(nèi)容(除了被@ApiIgnore指定的請求)。** @return*/@Beanpublic Docket createRestApi() {return new Docket(DocumentationType.SWAGGER_2) //標(biāo)明文檔類型 Swagger2.apiInfo(apiInfo()) //apiInfo()用來創(chuàng)建Api的基本信息(這些信息會(huì)展現(xiàn)在文檔頁面中).groupName("CloudE_Server") //組名.select() //select()函數(shù)返回一個(gè)ApiSelectorBuilder實(shí)例用來控制哪些接口暴露給Swagger來展現(xiàn).apis(RequestHandlerSelectors.basePackage("com.chuci.server.controller")) //掃描特定包下面的文件 還有.any 掃描所有包.paths(PathSelectors.any()) //Swagger會(huì)掃描該包下的所有Controller定義的API,并產(chǎn)生文檔內(nèi)容(除了被@ApiIgnore定義的請求).build().securityContexts(securityContexts()).securitySchemes(securitySchemes());}private List<? extends SecurityScheme> securitySchemes() { // 設(shè)置請求頭信息List<ApiKey> res = new ArrayList<>();ApiKey apiKey = new ApiKey("Authorization", "Authorization", "Header");res.add(apiKey);return res;}private List<SecurityContext> securityContexts() { // 設(shè)置需要認(rèn)證的路徑List<SecurityContext> res = new ArrayList<>();res.add(getContextByPath("/hello/.*"));return res;}private SecurityContext getContextByPath(String pathRegex) {return SecurityContext.builder().securityReferences(defaultAuth()).forPaths(PathSelectors.regex(pathRegex)).build();}private List<SecurityReference> defaultAuth() {List<SecurityReference> res = new ArrayList<>();AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything");AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];authorizationScopes[0] = authorizationScope;res.add(new SecurityReference("Authorization", authorizationScopes));return res;}private ApiInfo apiInfo() {return new ApiInfoBuilder().title("CloudE 接口文檔").description("物華天寶 , 龍光射牛斗之墟 \r"+ "人杰地靈 , 徐孺下陳蕃之榻\r"+ "------CloudE 接口文檔").termsOfServiceUrl("www.baidu.com").contact(new Contact("【楚辭】", "http://localhost:8081/doc.html", "自己郵箱地址")).version("1.0").build();} }

    同時(shí)為了測試,我們新建了HelloController。java文件進(jìn)行Swagger的測試
    我們通過域名:端口號/doc,html來訪問swagger

    3. 登錄驗(yàn)證

    未登錄狀態(tài)下去請求接口:

    提示未登錄,需要登錄。

    4. 添加驗(yàn)證碼模塊

    4.1 添加驗(yàn)證碼依賴

    這里采用谷歌的驗(yàn)證碼解決方案

    </dependency><!-- google kaptcha依賴 --><dependency><groupId>com.github.axet</groupId><artifactId>kaptcha</artifactId><version>0.0.9</version></dependency>

    4.2 添加驗(yàn)證碼配置文件


    新建CaptchaConfig配置文件,在這里進(jìn)行驗(yàn)證碼的一些設(shè)置,如邊框,字體大小,字體樣式等等。

    package com.chuci.server.config.captcha;import com.google.code.kaptcha.impl.DefaultKaptcha; import com.google.code.kaptcha.util.Config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration;import java.util.Properties;/*** 驗(yàn)證碼配置類** @Auther chuci* @Data 2022-01-15 18:04* @Description:*/ @Configuration public class CaptchaConfig {@Beanpublic DefaultKaptcha defaultKaptcha() {//驗(yàn)證碼生成器DefaultKaptcha defaultKaptcha = new DefaultKaptcha();//配置Properties properties = new Properties();//是否有邊框properties.setProperty("kaptcha.border", "yes");//設(shè)置邊框顏色properties.setProperty("kaptcha.border.color", "105,179,90");//邊框粗細(xì)度,默認(rèn)為1// properties.setProperty("kaptcha.border.thickness","1");//驗(yàn)證碼properties.setProperty("kaptcha.session.key", "code");//驗(yàn)證碼文本字符顏色 默認(rèn)為黑色properties.setProperty("kaptcha.textproducer.font.color", "blue");//設(shè)置字體樣式properties.setProperty("kaptcha.textproducer.font.names", "宋體,楷體,微軟雅黑");//字體大小,默認(rèn)40properties.setProperty("kaptcha.textproducer.font.size", "30");//驗(yàn)證碼文本字符內(nèi)容范圍 默認(rèn)為abced2345678gfynmnpwx// properties.setProperty("kaptcha.textproducer.char.string", "");//字符長度,默認(rèn)為5properties.setProperty("kaptcha.textproducer.char.length", "4");//字符間距 默認(rèn)為2properties.setProperty("kaptcha.textproducer.char.space", "4");//驗(yàn)證碼圖片寬度 默認(rèn)為200properties.setProperty("kaptcha.image.width", "100");//驗(yàn)證碼圖片高度 默認(rèn)為40properties.setProperty("kaptcha.image.height", "40");Config config = new Config(properties);defaultKaptcha.setConfig(config);return defaultKaptcha;}}

    4.3 驗(yàn)證碼生成

    package com.chuci.server.controller;import com.google.code.kaptcha.impl.DefaultKaptcha; import io.swagger.annotations.ApiOperation; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController;import javax.imageio.ImageIO; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.awt.image.BufferedImage; import java.io.IOException;/*** 驗(yàn)證碼** @Auther chuci* @Data 2022-01-15 18:14* @Description:*/ @RestController public class CaptchaController {@Autowiredprivate DefaultKaptcha defaultKaptcha;@ApiOperation(value = "驗(yàn)證碼")@GetMapping(value = "/captcha", produces = "image/jpeg")public void captcha(HttpServletRequest request, HttpServletResponse response){// 定義response輸出類型為image/jpeg類型response.setDateHeader("Expires", 0);// Set standard HTTP/1.1 no-cache headers.response.setHeader("Cache-Control", "no-store, no-cache, mustrevalidate");// Set IE extended HTTP/1.1 no-cache headers (use addHeader).response.addHeader("Cache-Control", "post-check=0, pre-check=0");// Set standard HTTP/1.0 no-cache header.response.setHeader("Pragma", "no-cache");// return a jpegresponse.setContentType("image/jpeg");//-------------------生成驗(yàn)證碼 begin --------------------------//獲取驗(yàn)證碼文本內(nèi)容String text = defaultKaptcha.createText();System.out.println("驗(yàn)證碼:" + text);//將驗(yàn)證碼放在session中request.getSession().setAttribute("captcha", text);//根據(jù)文本內(nèi)容創(chuàng)建圖片驗(yàn)證碼BufferedImage image = defaultKaptcha.createImage(text);ServletOutputStream outputStream = null;try {outputStream = response.getOutputStream();//輸出流輸出圖片,格式j(luò)pgImageIO.write(image, "jpg", outputStream);outputStream.flush();} catch (IOException e) {e.printStackTrace();}finally {if(outputStream != null){try {outputStream.close();} catch (IOException e) {e.printStackTrace();}}}//-------------------生成驗(yàn)證碼 end --------------------------} }

    重啟項(xiàng)目,我們可以看到swagger出現(xiàn)驗(yàn)證碼模塊,并且測試成功生成驗(yàn)證碼


    4.4 修改登錄傳遞參數(shù)

  • 修改AdminLoginParam文件,新增驗(yàn)證碼


  • 修改登錄Controller文件,傳遞參數(shù)新增驗(yàn)證碼部分


    同時(shí)修改Service層文件以及實(shí)現(xiàn)Imp層文件,并進(jìn)行驗(yàn)證碼正確性的檢測

  • // 驗(yàn)證碼檢測String captcha = request.getSession().getAttribute("captcha").toString();System.out.println("captcha:" + captcha + "; code:" + code);if(!StringUtils.hasLength(code) || !captcha.equalsIgnoreCase(code)){return SysResult.error("驗(yàn)證碼錯(cuò)誤,請重新輸入!");}

    5. 登錄成功

  • 驗(yàn)證碼錯(cuò)誤
  • 登錄成功
  • 登錄 成功,將返回的data信息中 tokenHead、token分別粘貼到swagger中Authorize頁面參數(shù)值輸入框中作為登錄token令牌,tokenHead與token之間使用空格隔開
  • "tokenHead": "Bearer" "token": "eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJhZG1pbiIsImNyZWF0ZWQiOjE2NDI2NjUwMzc4OTYsImV4cCI6MTY0MzI2OTgzN30.iVkznvdJ3DCCVSdVbCBN34nz_BG1JGXyfolJ5GLH7_uIZvEcMHLAzc6q8Hkzqx8AX_d7VEH_wk20mrbtk3HvgA"


    再次進(jìn)行接口調(diào)用,則會(huì)帶如剛剛的參數(shù)值token令牌進(jìn)行登錄驗(yàn)證。



    致此,整個(gè)登錄模塊已完成,等待前端頁面調(diào)用驗(yàn)證即可。


    至此,本節(jié)完~~~

    上一節(jié): Cloud E隨筆-后端_piece2–代碼生成器
    下一節(jié):

    此系列以完整記錄自己項(xiàng)目經(jīng)歷此系列以完整記錄自己項(xiàng)目經(jīng)歷 項(xiàng)經(jīng)

    總結(jié)

    以上是生活随笔為你收集整理的Cloud E随笔-后端_piece3--实现登录功能的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。

    99热这里是精品 | 91亚洲在线 | 国产91国语对白在线 | 色瓜 | 日韩免费高清在线观看 | 欧美一级黄色视屏 | 国产精品高清在线观看 | 国产香蕉视频在线播放 | 蜜臀av夜夜澡人人爽人人 | 国产精品久久久久婷婷 | 国产生活一级片 | 国产精品1区2区3区 久久免费视频7 | 日韩av在线一区二区 | 日韩三级不卡 | 天天爱天天操天天射 | 91在线精品播放 | 亚洲精品字幕在线观看 | 中文字幕国产视频 | 日日草夜夜操 | 国产网红在线观看 | 免费在线观看av不卡 | 久久免费a | 久久久69 | 五月天天色 | 久久精品9| 久久九九国产视频 | 麻豆成人小视频 | 中文字幕在线观看资源 | 日韩激情精品 | 国产一级一片免费播放放a 一区二区三区国产欧美 | 中文字幕在线视频免费播放 | 久久官网 | 一区二区三区四区在线免费观看 | 亚洲福利精品 | avhd高清在线谜片 | 久久成人国产精品一区二区 | 亚洲国产视频直播 | 国产一二三精品 | 久操伊人 | 青春草免费在线视频 | 在线播放亚洲激情 | 韩国一区二区三区在线观看 | 免费在线观看av不卡 | 麻豆久久一区二区 | 免费看av在线 | 久久国产精品99久久人人澡 | 天天色天天上天天操 | 超级av在线| 成年人在线电影 | 夜夜骑首页 | 黄色午夜| 五月婷婷六月丁香在线观看 | 精品二区久久 | 国产精品久久久久久吹潮天美传媒 | 亚洲精品大全 | 国产99久久久国产精品免费二区 | 狠狠狠狠狠狠操 | 狠狠干狠狠久久 | 免费看污的网站 | 久久与婷婷 | 精品国产伦一区二区三区 | 欧美日韩二三区 | 偷拍精偷拍精品欧洲亚洲网站 | 成人av亚洲 | 一本一本久久a久久 | 天天操欧美 | 一级黄色片在线观看 | 婷婷国产精品 | 国内综合精品午夜久久资源 | 天天操天天谢 | 日本中文字幕高清 | 日本视频久久久 | 99视频在线免费看 | 岛国精品一区二区 | 偷拍视频一区 | 国产综合小视频 | 最新av在线播放 | 在线中文字幕播放 | 91精品在线观看视频 | 国产亚洲一级高清 | 亚洲天堂免费视频 | 久久理论片 | 国产黄大片 | 中文字幕高清免费日韩视频在线 | 黄色三级在线看 | 成人a免费视频 | 狠狠色婷婷丁香六月 | 亚洲一区美女视频在线观看免费 | 亚洲视频久久 | 麻豆免费在线视频 | 日韩免费视频在线观看 | 激情综合五月网 | 91最新中文字幕 | 国产精品国产三级在线专区 | 亚洲综合欧美日韩狠狠色 | 草免费视频| 六月激情 | 久草观看视频 | 色的网站在线观看 | 99热这里只有精品免费 | 亚洲男模gay裸体gay | 色在线网站 | 久久天天操 | 夜夜躁狠狠躁 | 天天躁天天操 | 国产精品久久久久av福利动漫 | 中文字幕中文字幕 | 久久99久久99精品中文字幕 | 国产青青青 | 91色亚洲| 欧美成人影音 | 九九综合久久 | 99色| 免费福利在线观看 | 天天天天天操 | 国产黄a三级三级三级三级三级 | 91香蕉国产 | 在线观看视频 | 欧美精品一区二区免费 | 日韩成人邪恶影片 | 一区二区三区四区五区在线视频 | www.夜色321.com | 天天色.com| 成人av一区二区在线观看 | 99精品在线观看视频 | 中文字幕国产一区二区 | 亚洲成人动漫在线观看 | 99综合电影在线视频 | 夜色成人av | 日韩h在线观看 | 91免费观看视频网站 | 人人爱人人添 | 啪嗒啪嗒免费观看完整版 | 久久国产精品免费观看 | 色天天中文 | 亚洲精品av在线 | 成人一级在线 | 97电影手机版 | 国产亚洲精品久久久久久移动网络 | 久久精品一级片 | 日韩不卡高清视频 | 日韩欧美99 | 日韩在线观看一区二区 | 中文字幕资源在线 | 国产美女在线精品免费观看 | 国产在线观看一 | 久久国产一区二区三区 | 国产99久久精品一区二区永久免费 | 国产精品中文久久久久久久 | 国产高清专区 | 久久久久亚洲精品成人网小说 | 美女国内精品自产拍在线播放 | 精品产品国产在线不卡 | 成人啪啪18免费游戏链接 | 欧美激情视频在线观看免费 | www.91国产| 亚洲年轻女教师毛茸茸 | 最新日韩中文字幕 | 免费一级片视频 | 欧美analxxxx| 日韩视频1区 | 日韩免费 | 中文有码在线视频 | 色婷婷中文 | 国产一区二区三区网站 | 国产精品免费视频网站 | 国产护士hd高朝护士1 | 午夜国产福利在线 | 婷婷成人综合 | 免费久久99精品国产 | 中文字幕在线专区 | 天天天天综合 | 色老板在线 | 久草在线视频首页 | 最近高清中文在线字幕在线观看 | 最近中文字幕免费 | 综合久久一本 | 综合激情婷婷 | 亚洲aⅴ一区二区三区 | 麻豆91精品视频 | 中文字幕 国产视频 | 人人爽人人澡 | 激情开心网站 | 一级片黄色片网站 | 天天做天天干 | 国产亚洲精品久久久久久电影 | 91污视频在线观看 | 综合在线亚洲 | 好看av在线 | 国产欧美精品xxxx另类 | 91精品久久久久久久久久久久久 | 天天操夜夜摸 | 日韩精品一区二区在线观看视频 | 亚洲精品456在线播放乱码 | 国产精品原创在线 | 欧美一级特黄aaaaaa大片在线观看 | 免费在线观看成人av | 免费看的黄色的网站 | 成人午夜精品久久久久久久3d | 国产一区二区影院 | a视频在线播放 | 欧美精品一区二区三区一线天视频 | zzijzzij亚洲日本少妇熟睡 | 日日爽 | 4438全国亚洲精品在线观看视频 | 成年人免费在线 | 国产91免费在线观看 | 久久三级毛片 | 一级片视频在线 | 亚洲精品美女久久久久 | 久久免费成人精品视频 | 嫩嫩影院理论片 | 免费亚洲视频 | 国产精品久久久久9999 | 97在线看片 | 欧美日韩视频在线观看免费 | 中文字幕一区二区三区精华液 | 日韩欧美一区二区在线观看 | 国产美女精品视频 | 婷婷爱五月天 | 有码视频在线观看 | 久久中文字幕在线视频 | 天天做日日爱夜夜爽 | 久久午夜国产精品 | 久久综合五月婷婷 | 操天天操| 免费无遮挡动漫网站 | 亚洲欧美日韩在线一区二区 | 久久只精品99品免费久23小说 | 美女视频又黄又免费 | 欧美久久久久久久久久久久 | 亚洲综合色播 | 99视频免费看 | 精品在线观 | 国产aaa免费视频 | 午夜精品久久久99热福利 | 高清在线一区二区 | av亚洲产国偷v产偷v自拍小说 | 激情五月网站 | 香蕉久久国产 | 成人毛片100免费观看 | 亚洲欧美日韩一级 | 欧美日韩国内在线 | 国产在线 一区二区三区 | 日批视频在线播放 | 国产精品成人av久久 | 福利视频一区二区 | 精品欧美一区二区在线观看 | 国产一区二区在线精品 | 99视频在线观看一区三区 | 夜色资源站wwwcom | 一区二区三区视频网站 | 国产麻豆精品久久一二三 | 日本护士撒尿xxxx18 | 欧美日韩另类在线观看 | 97视频久久久| 亚洲婷婷综合色高清在线 | 国产午夜在线观看视频 | 亚洲精品乱码久久久久久高潮 | 亚洲日本激情 | 日日夜夜精品免费 | 日韩在线国产 | av一区在线 | 国产精品色婷婷 | 美女视频又黄又免费 | av免费在线观 | 在线亚洲高清视频 | av黄色av | 亚洲欧美在线视频免费 | 免费观看9x视频网站在线观看 | 亚洲国产精品成人va在线观看 | 美国人与动物xxxx | 国产精品久99| 最新av免费在线 | 91精品一区国产高清在线gif | 欧美a性 | 亚洲国产精品成人精品 | 在线天堂视频 | 天天综合网天天综合色 | 丁香五香天综合情 | 亚洲精品资源在线 | 久久综合在线 | 久久精品综合网 | 国产精品久久久久久五月尺 | 欧美激情奇米色 | 日韩欧美高清一区二区三区 | 九九免费精品视频在线观看 | 亚洲一二三区精品 | 国产精品无 | 中文字幕在线看视频国产中文版 | 国产成人av一区二区三区在线观看 | 91九色精品国产 | 日韩电影在线视频 | 国内99视频| 色在线视频 | 我要看黄色一级片 | 国产成人香蕉 | 日本精品一区二区三区在线播放视频 | 中文字幕av在线免费 | 97成人免费视频 | 亚洲精品国产自产拍在线观看 | 操操操综合 | 国产精品久久久区三区天天噜 | 77国产精品| 99国内精品久久久久久久 | 99草在线视频 | 久久九九网站 | 免费看污在线观看 | 日韩在线理论 | 人人干狠狠操 | 色999视频 | 久操视频在线免费看 | 久久五月精品 | 成人a视频| 99久久婷婷国产一区二区三区 | 在线国产欧美 | 91麻豆精品国产91久久久无需广告 | 美女网站视频久久 | 国产特级毛片aaaaaa高清 | 五月婷婷婷婷婷 | 久草在线视频首页 | 91av视频网站| 精品久久九九 | 在线观看一区 | 成人h电影| 五月天丁香综合 | 韩国在线一区二区 | 国产精品观看在线亚洲人成网 | 亚洲精品乱码久久久久久 | 亚洲精品久久久久999中文字幕 | 免费观看第二部31集 | 天天综合视频在线观看 | 精品一区91 | 国产亚洲精品无 | 欧美-第1页-屁屁影院 | 欧美aa级| 日韩在线大片 | 人人干人人模 | 香蕉视频在线网站 | 亚洲精品网址在线观看 | 亚洲一级片在线观看 | 天天干天天爽 | 国产色视频一区 | 日韩欧美在线视频一区二区 | 超级碰碰碰视频 | 黄色av电影| 亚洲一区二区三区四区在线视频 | 狠狠操91| 中文在线a√在线 | 日日夜夜狠狠干 | 精品电影一区 | 美女网站视频久久 | 少妇bbb搡bbbb搡bbbb | 少妇自拍av | 手机在线欧美 | 在线观看亚洲 | 人人爱人人舔 | 久久精品国产第一区二区三区 | 久久人人爽人人爽人人片av免费 | 国产专区在线视频 | 亚洲天堂网视频在线观看 | 日本午夜免费福利视频 | 九九热在线免费观看 | 日韩成人免费在线电影 | 在线国产日韩 | 久久成年人 | 久久久久久久久久久高潮一区二区 | 亚洲精品视频在线 | 亚洲jizzjizz日本少妇 | 天天曰天天曰 | 国产精彩视频 | 国产在线精品国自产拍影院 | 水蜜桃亚洲一二三四在线 | 天天插天天射 | 婷婷六月天综合 | 久草在线久草在线2 | 久久久久美女 | 日韩av免费一区二区 | 亚洲爱视频| 狠狠色丁香婷婷综合久小说久 | 国产伦理久久 | 特级a老妇做爰全过程 | 国产精品一区专区欧美日韩 | 欧美日韩国产免费视频 | 色婷婷成人| 日产乱码一二三区别在线 | 亚洲视频精品在线 | 国产一区二区三区高清播放 | 狠狠干在线播放 | 天天精品视频 | 欧美大jb| 毛片随便看| 国产一区二三区好的 | 亚洲精品视频免费在线 | 激情婷婷综合 | 91福利在线观看 | 欧美人交a欧美精品 | 免费观看一级成人毛片 | 成人a免费视频 | 日本中文字幕在线电影 | 久久不卡国产精品一区二区 | 欧美视频在线观看免费网址 | 久久久一本精品99久久精品 | 911国产在线观看 | 69热国产视频 | 日日夜夜操操操操 | 天天狠狠干 | 久久久久久免费 | 中文字幕精品一区久久久久 | 精品久久久成人 | 999视频在线播放 | 欧美a视频在线观看 | 91粉色视频| 免费日韩一区二区三区 | 国产日本在线 | 91精品在线视频 | 日韩区视频| 一级片视频在线 | 天天爱天天爽 | 欧美 日韩 国产 中文字幕 | 欧美日韩二区在线 | 精品久久视频 | 国产麻豆精品传媒av国产下载 | 激情综合国产 | 国产精品久久久久久久久大全 | 一区二区精品国产 | 日日日日日 | 九九热视频在线 | 99精品在线播放 | 日韩免费看视频 | 欧美日韩精品免费观看 | 国产成人1区 | 美女视频黄是免费的 | 9热精品| 久久免费电影网 | 免费国产在线精品 | 久久国产网站 | 99精品免费在线观看 | 99婷婷狠狠成为人免费视频 | 久草久视频 | www.香蕉视频| 国产特级毛片aaaaaaa高清 | 五月婷婷,六月丁香 | 毛片视频网址 | www.久久色 | 久草在线综合网 | 免费a级观看| 久久99精品久久久久久久久久久久 | 狠狠色丁香婷综合久久 | 99精品国产aⅴ | 国产 日韩 欧美 自拍 | 免费a视频在线观看 | 日本性生活一级片 | www夜夜| 亚洲精品在线播放视频 | 99久久99久国产黄毛片 | 免费在线看成人av | av免费网站在线观看 | 五月天色婷婷丁香 | 免费在线一区二区三区 | 欧美一区二区三区四区夜夜大片 | 亚洲精品1234区 | 成人午夜影院在线观看 | 99国内精品久久久久久久 | 99这里精品 | 午夜999 | 美女露久久 | 久久久天堂 | 久草网在线观看 | 在线观看免费黄视频 | 久久麻豆视频 | 成年人看片网站 | 欧美成人一区二区 | 91完整版在线观看 | 日韩免费电影网站 | 草久久久久久 | 国产成人精品在线播放 | 久久一区二区三区超碰国产精品 | 98超碰人人 | 久热爱| a视频在线 | 国产精品18久久久久久久久久久久 | 蜜桃视频在线视频 | 成人av电影免费观看 | 99999精品 | 免费男女羞羞的视频网站中文字幕 | 免费中午字幕无吗 | 久久艹在线观看 | 国产美女网站在线观看 | 日本高清中文字幕有码在线 | 婷婷色网| 黄色免费网站下载 | 午夜999 | 国产无限资源在线观看 | 一级黄色片在线免费观看 | 丁香花在线观看视频在线 | 成人午夜剧场在线观看 | 黄色亚洲片 | 成人免费一区二区三区在线观看 | 国产一级免费观看视频 | 国产精品一区二区免费在线观看 | 国产精品中文字幕在线观看 | 成人一级在线观看 | 97超在线| 97高清视频 | 久久免费视频99 | 日韩免费电影网站 | 午夜久草 | 日韩大片在线免费观看 | 欧美精品久久久久久久久免 | 成人一区影院 | 久热国产视频 | 国产视频第二页 | 欧美国产日韩在线视频 | 天天操天天操天天 | 久久免费在线观看 | 国产色啪| 国产视频一区在线播放 | 永久免费av在线播放 | 精品夜夜嗨av一区二区三区 | 久草在线网址 | 在线天堂中文在线资源网 | 成人免费视频视频在线观看 免费 | 美女一级毛片视频 | 婷婷丁香狠狠爱 | 日本性生活一级片 | a视频免费在线观看 | 免费看片黄色 | 人人干人人超 | 国产偷国产偷亚洲清高 | 91漂亮少妇露脸在线播放 | 97夜夜澡人人双人人人喊 | 色永久免费视频 | 涩涩爱夜夜爱 | 婷婷午夜天| 国产婷婷久久 | 欧美日韩视频在线观看免费 | 五月在线视频 | 伊人www22综合色 | 精品国产99 | 免费在线激情电影 | 日韩免费| 天天激情综合网 | 激情五月五月婷婷 | 国精产品一二三线999 | 精品视频免费观看 | 国产成人精品综合 | 欧美日韩视频在线观看免费 | 亚洲综合激情五月 | 欧美日韩一区二区三区不卡 | 黄a网| av福利网址导航大全 | 天天色天天射天天综合网 | 免费成人在线观看视频 | 黄色av一区 | 国产不卡高清 | av黄色影院 | 色九色| 少妇av网| 久久久免费网站 | 日韩精品一区二区三区水蜜桃 | 久久精品一二三 | 丁香一区二区 | 91成人观看 | 亚洲精品国偷自产在线91正片 | 亚洲婷婷免费 | 97成人精品 | 日韩av在线网站 | 日本黄色黄网站 | 免费视频网 | 色视频在线观看 | 丁香影院在线 | 久久久免费国产 | 一区二区久久久久 | 久久久久久久久久久福利 | 久久99久久99 | 成人免费视频网站 | 色婷婷视频网 | 日韩精品一区二区三区免费观看 | ,午夜性刺激免费看视频 | 久久免费电影 | 在线观看黄网 | 亚洲热久久| 国偷自产中文字幕亚洲手机在线 | 色免费在线 | 香蕉影院在线观看 | 成人超碰在线 | 久久久综合香蕉尹人综合网 | 国产一区二区在线免费播放 | 国产小视频在线看 | 久久免费中文视频 | 国产精品美女视频网站 | 不卡视频国产 | 久草在线资源免费 | 日韩高清一区在线 | 久久视频6 | 久久国产精彩视频 | 国产精品人成电影在线观看 | 午夜影视av | 国产精品久久久久久久久大全 | 正在播放国产一区二区 | 久久久人人人 | 亚洲精品午夜国产va久久成人 | 日韩偷拍精品 | 4438全国亚洲精品观看视频 | 免费福利在线 | 亚洲欧洲日韩 | 国产尤物一区二区三区 | 亚洲电影久久 | 国产精品一区二区三区在线播放 | 欧美国产日韩中文 | 免费国产视频 | 国产一区私人高清影院 | 久草在线资源观看 | 99久久99视频只有精品 | 日韩中文字幕免费在线播放 | 欧美日韩视频在线观看一区二区 | 亚洲国产高清在线 | 激情综合电影网 | 亚洲精品黄网站 | 天天激情在线 | 久久久午夜精品理论片中文字幕 | 激情开心色 | 天天爽天天爽夜夜爽 | 欧美视频www | 天天躁天天操 | 日本在线观看黄色 | 99热精品免费观看 | 日本色小说视频 | 久久成人在线 | 中文字幕有码在线观看 | 国产精品色 | 欧美另类高潮 | 亚洲va韩国va欧美va精四季 | 国产精品久久久一区二区 | 亚洲视频中文 | 欧美精选一区二区三区 | 久久久久久久久免费视频 | 欧美视频在线二区 | 91毛片在线观看 | 日韩3区| 欧美亚洲另类在线视频 | 在线观看完整版免费 | 91粉色视频 | 一区二区三区精品在线 | 99一区二区三区 | 99久久影视 | 久久综合九色 | 黄色在线观看网站 | 亚洲精品18日本一区app | 成人午夜影视 | 日韩成人欧美 | 天天草av | 五月综合激情网 | 久久久伊人网 | 国产精品私人影院 | 久久综合给合久久狠狠色 | 国产最顶级的黄色片在线免费观看 | 国产在线污| 国产精品99久久久久人中文网介绍 | 国产精品久久久久永久免费 | 正在播放国产一区 | 欧美一级裸体视频 | 免费高清在线一区 | 五月综合激情网 | 日韩在线观看精品 | 国产精品av免费 | 91麻豆网站| 亚洲一区二区精品在线 | 天天操一操 | 免费成人av网站 | 91av欧美| 久久一区二 | av亚洲产国偷v产偷v自拍小说 | 成人毛片一区 | 午夜色站| 天天操天天操一操 | 色999精品 | 国产精品18久久久久久久久 | 免费热情视频 | 一级理论片在线观看 | 久久久久国产a免费观看rela | 新版资源中文在线观看 | 久热这里有精品 | 国产精品久一 | 日韩综合一区二区三区 | avav片| 亚洲欧洲国产视频 | 久久久久久久国产精品视频 | 特级aaa毛片 | 欧美日韩在线视频一区二区 | 黄色网址在线播放 | 五月天久久综合 | 中文字幕在线有码 | 国产资源在线免费观看 | 午夜婷婷在线播放 | 国产视频一级 | 成人午夜精品福利免费 | 久久久久久久久久久久国产精品 | 欧美日韩视频精品 | 97香蕉视频 | 在线观看日本高清mv视频 | 人人射| 在线观看 国产 | 成人在线观看资源 | 日韩v欧美v日本v亚洲v国产v | 亚洲精品88欧美一区二区 | 成人久久久精品国产乱码一区二区 | 天天干天天操av | 久草视频免费在线播放 | 在线观看免费观看在线91 | 性色大片在线观看 | 成人动态视频 | 天天干亚洲 | 激情深爱.com | 日韩有色 | 免费三级影片 | www.av免费 | 在线免费中文字幕 | 99综合电影在线视频 | 欧美日韩中文在线 | 在线精品播放 | 久久图| 在线电影a | 欧美久久综合 | 精品久久久久久综合日本 | 亚洲一级影院 | 亚洲午夜激情网 | 人人爽人人爽人人片 | 日韩免费网址 | 亚洲视频精选 | 国产手机av在线 | 九九热免费视频在线观看 | 天天拍夜夜拍 | 国产99久久久国产 | 999ZYZ玖玖资源站永久 | 久草视频在线资源站 | 久久国产精品一区二区三区 | 婷婷丁香色 | 日韩欧美aaa | 中文在线8新资源库 | 在线免费观看国产视频 | 美女视频黄免费的久久 | 亚洲黄色大片 | 五月综合色 | 波多野结衣视频在线 | 欧美一级免费在线 | 成片免费观看视频大全 | bayu135国产精品视频 | 五月开心综合 | 成年人网站免费在线观看 | 国产高清视频在线播放 | 成 人 黄 色 视频播放1 | 人人干人人干人人干 | 国产a国产a国产a | 久久国产精品成人免费浪潮 | 97精品国产97久久久久久春色 | 久久久久国 | 色综合久久精品 | 日韩免费看的电影 | 1000部18岁以下禁看视频 | 成年人黄色免费网站 | 一区二区三区在线免费观看视频 | 日韩高清成人 | 国产黄色大片 | 欧美精品二区 | 免费三级av| 亚洲春色综合另类校园电影 | 国产精品丝袜在线 | 色婷婷久久久综合中文字幕 | 综合网伊人| 欧美一级性生活 | 日韩精品不卡在线 | 精品久久福利 | 日韩欧美一区二区在线观看 | 久久经典国产 | 国产麻豆精品传媒av国产下载 | 欧美极品少妇xxxxⅹ欧美极品少妇xxxx亚洲精品 | 伊人狠狠 | 国产精品女人久久久久久 | 国产精品大片免费观看 | 国产小视频免费在线网址 | 热久久视久久精品18亚洲精品 | 欧美激情视频一二区 | 亚洲永久精品在线观看 | 麻豆视频在线 | 久久久在线视频 | 国产成人精品亚洲日本在线观看 | 日韩精品中文字幕久久臀 | 国产在线欧美日韩 | 成人在线视频在线观看 | 国产精品日韩在线 | 久久免费99精品久久久久久 | 久久综合久色欧美综合狠狠 | 欧美日韩免费视频 | 国产精品一区电影 | 精品a在线 | 久草网在线观看 | 亚洲成色777777在线观看影院 | 国产视频在线观看一区 | 在线观看免费 | 一级a性色生活片久久毛片波多野 | 美女一区网站 | 中文字幕在线观看完整版电影 | 国产一区二区免费 | 日韩中文久久 | 国产精品黄色 | 日韩婷婷 | 亚洲激情久久 | 天天爱天天 | 中文字幕av最新更新 | 亚洲欧美日韩国产精品一区午夜 | 九九热中文字幕 | 日日久视频 | 日韩欧美精品一区二区三区经典 | 黄色软件在线观看 | 1000部国产精品成人观看 | 日韩午夜在线观看 | 久久香蕉电影 | 欧美精品天堂 | av片在线观看 | 麻豆免费看片 | 一级片在线 | 久精品视频 | 婷婷六月天丁香 | 免费a级毛片在线看 | 国产小视频免费在线观看 | 久久99网| 91日韩精品一区 | 成人国产电影在线观看 | 国产视频久 | 一区二区三区在线观看中文字幕 | 国产视频一区二区在线 | 国产麻豆视频免费观看 | 在线视频你懂得 | 99久久日韩精品视频免费在线观看 | 黄色免费在线视频 | 国产综合精品一区二区三区 | 色婷婷激情网 | 女人18毛片a级毛片一区二区 | 欧美日韩在线免费观看 | 不卡的av在线 | 久草电影免费在线观看 | 少妇av网 | 亚洲综合欧美日韩狠狠色 | 欧美午夜a| 日韩色区 | 欧美在线观看视频一区二区三区 | 啪啪激情网| 丁香色综合| 精品九九九 | 天天操天天能 | 国产精品久久久av久久久 | 久久精品视频免费播放 | 又爽又黄又无遮挡网站动态图 | 91人人插 | 7777xxxx| 夜添久久精品亚洲国产精品 | 米奇影视7777 | 亚洲高清久久久 | 夜夜夜夜猛噜噜噜噜噜初音未来 | 日韩在线视 | 99这里都是精品 | 成人av地址 | 亚洲伊人网在线观看 | 91毛片在线 | 亚洲春色综合另类校园电影 | 国产小视频免费观看 | 国际精品久久 | 色999在线 | 日韩av电影手机在线观看 | 国产一级片免费播放 | 成人a毛片| 日韩三级一区 | 中文字幕在线观看三区 | 亚洲一区二区天堂 | 日韩在线视频观看 | 国产精品 中文在线 | 欧美综合色 | 日韩久久精品一区二区 | 中文字幕第一页在线 | 狠狠综合久久av | 国产精品久久久久一区二区三区 | 99福利影院| 国产成人久久av免费高清密臂 | av网址最新 | 18国产精品白浆在线观看免费 | 婷婷在线视频 | 91精品国产99久久久久久久 | 伊人国产在线观看 | 成年人在线观看免费视频 | 一区二区三区精品久久久 | 一区二区理论片 | 九九九在线| 亚洲激情在线观看 | 天天天天天天天天操 | 久久精品一二区 | 久久久成人精品 | 久久精品99国产精品 | 在线v片免费观看视频 | 综合色站 | 亚洲精品久久久久中文字幕二区 | 97看片| 精品国产一区二区三区不卡 | 国产精华国产精品 | 欧美性爽爽 | 又黄又爽的免费高潮视频 | 99热国产精品 | 欧美激情第八页 | 亚洲精品一区二区久 | 2018好看的中文在线观看 | 色综合天天综合在线视频 | 91片黄在线观 | 成年人在线视频观看 | 久久综合九色综合97婷婷女人 | 99看视频在线观看 | 国产精品久久久久久久免费大片 | 国产精品久久99 | 亚洲开心色 | 亚洲一区精品二人人爽久久 | 国产传媒一区在线 | 国产中文字幕在线视频 | 久久人人添人人爽添人人88v | 久久久久成人精品 | 亚洲黑丝少妇 | 最近日韩免费视频 | 91看片淫黄大片在线播放 | 亚洲精品国产精品国自产在线 | 黄色电影网站在线观看 | 在线国产91 | 久久久国产精品人人片99精片欧美一 | 国产丝袜在线 | 综合网久久| 久草在线观看资源 | 国产偷国产偷亚洲清高 | 成人免费观看完整版电影 | 成人网页在线免费观看 | 久久久精品免费观看 | 国产老妇av | 久久精品一区二区三区中文字幕 | 久久久三级视频 | 久久草草热国产精品直播 | 在线观看成年人 | 久久久久久久99精品免费观看 | 成人av在线资源 | 24小时日本在线www免费的 | 亚洲精品乱码久久久一二三 | 久草干| 欧美一级日韩三级 | 国产人在线成免费视频 | 亚州精品天堂中文字幕 | 日本三级吹潮在线 | av丝袜制服 | 在线观看网站av | 国产精品破处视频 | 国内精品久久久久久久影视简单 | 色综合久久久久综合99 | 在线观看国产高清视频 | 手机在线观看国产精品 | 91丨九色丨国产在线观看 | 中文字幕在线观看第一区 | 五月综合激情婷婷 | 国产性xxxx| 在线观看亚洲免费视频 | 91九色视频| 国产精品永久久久久久久www | 黄色一级大片在线免费看国产一 | 国产高清黄 | 激情av资源| 欧美a级片免费看 | 国产经典 欧美精品 | 免费观看www视频 | 成人免费观看a | 久久久久亚洲精品成人网小说 | 亚洲免费婷婷 | 午夜久久成人 | 天天干天天射天天插 | 久久免费在线观看视频 | 欧美做受高潮 | 国产一区二区三区四区大秀 | 国产五码一区 | 最近中文字幕免费 | www91在线观看 | 九九九九九九精品任你躁 | 国产手机在线视频 | av在线播放亚洲 | 亚洲精品免费观看视频 | 国产一区在线视频播放 | 日韩精品字幕 | 国产精品va | 日韩欧美高清在线 | 天堂av官网 | 五月天久久狠狠 | 久久久久久伊人 | 亚洲 欧美 成人 | 亚洲国产精品500在线观看 | 97超级碰碰碰视频在线观看 | 免费av网站观看 |