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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

spring boot结合shiro实现用户-角色-权限的控制(包含用户名密码登陆和手机号验证码登陆)

發(fā)布時間:2024/3/13 编程问答 52 豆豆
生活随笔 收集整理的這篇文章主要介紹了 spring boot结合shiro实现用户-角色-权限的控制(包含用户名密码登陆和手机号验证码登陆) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

spring boot整合shiro實現(xiàn)權(quán)限校驗

1.首先導(dǎo)入項目所需jar包

<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.1.3.RELEASE</version><relativePath/></parent><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding><java.version>1.8</java.version><spring-cloud.version>Greenwich.RELEASE</spring-cloud.version><mysql.version>5.1.47</mysql.version><mybaitsPlus.version>3.1.1</mybaitsPlus.version><druid.version>1.0.31</druid.version><shiro-redis.version>3.1.0</shiro-redis.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><!--devtools熱部署--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><optional>true</optional><scope>runtime</scope></dependency><!-- mysql驅(qū)動 --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.47</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.1.1</version></dependency><!--redis存儲--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency><dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-core</artifactId><version>1.4.0</version></dependency><dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-spring</artifactId><version>1.4.0</version></dependency><dependency><groupId>org.apache.commons</groupId><artifactId>commons-lang3</artifactId><version>3.9</version><scope>compile</scope></dependency><!-- Shiro-redis插件 --><dependency><groupId>org.crazycake</groupId><artifactId>shiro-redis</artifactId><version>${shiro-redis.version}</version></dependency><dependency><groupId>org.springframework.session</groupId><artifactId>spring-session-data-redis</artifactId></dependency><dependency><groupId>org.springframework.session</groupId><artifactId>spring-session</artifactId><version>1.3.5.RELEASE</version></dependency><dependency><groupId>com.sun</groupId><artifactId>tools</artifactId><version>1.8.0</version><scope>system</scope><systemPath>${env.JAVA_HOME}/lib/tools.jar</systemPath><optional>true</optional></dependency><!-- 分頁插件 --></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><configuration><fork>true</fork></configuration></plugin></plugins></build>

2. 編寫yml和properties配置文件

yml文件

server:port: 8083#tomcat:#max-http-post-size: -1max-http-header-size: 4048576 spring:profiles:active: diagnoseapplication:name: user-centerdevtools:restart:enabled: true # 設(shè)置開啟熱部署additional-paths: src/main/java # 重啟目錄exclude: WEB-INF/**freemarker:cache: false # 頁面不加載緩存,修改即時生效datasource:driver-class-name: com.mysql.jdbc.Driverurl: jdbc:mysql://192.168.1.199/zhzd?useUnicode=true&characterEncoding=utf-8&useSSL=falseusername: rootpassword: root# myBatis-plus mybatis-plus:#configuration:#log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 輸出sql日志和查詢結(jié)果日志mapper-locations: classpath*:mapper/**Mapper.xml # .xml目錄type-aliases-package: com.etouch.mapper # 接口包global-config:db-config:db-type: mysqlcolumn-underline=true: # 默認(rèn)駝峰# 只打印sql日志和sql參數(shù) logging:file: logs/sys.loglevel:com:etouch:mapper: debug# shiro自定義配置 shiro:session:jsessionid: x-auth-tokenrole:superRole: superAdmin--- # Redis數(shù)據(jù)源 spring:profiles: diagnoseredis:host: localhostport: 6379timeout: 6000password: nulldatabase: 0jedis:pool:max-active: 1000 # 連接池最大連接數(shù)(使用負(fù)值表示沒有限制)max-wait: -1 # 連接池最大阻塞等待時間(使用負(fù)值表示沒有限制)max-idle: 10 # 連接池中的最大空閑連接min-idle: 5 # 連接池中的最小空閑連接 eureka:instance:prefer-ip-address: trueinstance-id: user-centerlease-expiration-duration-in-seconds: 15lease-renewal-interval-in-seconds: 5client:service-url:defaultZone: http://eureka:eureka@localhost:8800/eureka/registry-fetch-interval-seconds: 5

properties文件

#redis 中存儲的用戶登錄數(shù)據(jù)結(jié)構(gòu) user.login.redis=zhzd:user:login: #redis 中存儲的驗證碼結(jié)構(gòu) user.send.code=zhzd:user:code: #redis 中存儲的用戶信息 user.info.dto=zhzd:user:login:dto:

3.新增MyShiroRealm繼承AuthorizingRealm,

package com.etouch.config.shiro;import com.etouch.DTO.MenuDTO; import com.etouch.DTO.RoleDTO; import com.etouch.DTO.UserDTO; import com.etouch.corecenter.utils.UuidUtils; import com.etouch.entity.SysMenu; import com.etouch.entity.SysRole; import com.etouch.entity.SysUser; import com.etouch.entity.SysUserToken; import com.etouch.service.SysUserTokenService; import com.etouch.service.UserService; import com.etouch.utils.ShiroUtils; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.*; import org.apache.shiro.authz.AuthorizationInfo; import org.apache.shiro.authz.SimpleAuthorizationInfo; import org.apache.shiro.realm.AuthorizingRealm; import org.apache.shiro.subject.PrincipalCollection; import org.springframework.beans.factory.annotation.Autowired;public class MyShiroRealm extends AuthorizingRealm {@Autowiredprivate UserService userService;/*** 權(quán)限校驗** @param principals* @return*/@Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();UserDTO user = (UserDTO) SecurityUtils.getSubject().getPrincipal();UserDTO userDTO = userService.findUserByName(user.getLoginName());for (RoleDTO role : userDTO.getRoleList()) {authorizationInfo.addRole(role.getRoleName());for (MenuDTO menu : role.getMenuDTOList()) {authorizationInfo.addStringPermission(menu.getMenuUrl());}}return authorizationInfo;}/*** 登錄認(rèn)證** @param token* @return* @throws AuthenticationException*/@Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {//強轉(zhuǎn)成自己傳入的參數(shù),要不然獲取不到自己傳入的用戶名和密碼UsernamePasswordToken upToken = (UsernamePasswordToken) token;//獲得前臺輸入的用戶名和密碼String username = upToken.getUsername();String password = new String(upToken.getPassword());//根據(jù)郵箱獲得數(shù)據(jù)庫的用戶UserDTO user = userService.findUserByName(username);if (user == null) {return null; //return null 在底層會拋出異常}SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, user.getPassword(), this.getName());return info;}/* // 清除緩存public void clearCached() {PrincipalCollection principals = SecurityUtils.getSubject().getPrincipals();super.clearCache(principals);}*/

4. 新增動態(tài)獲取權(quán)限, 校驗權(quán)限業(yè)務(wù)類

接口類

package com.etouch.config.shiro.service;import org.apache.shiro.spring.web.ShiroFilterFactoryBean;import java.util.Map;/*** <p> shiro權(quán)限處理 </p>*/ public interface ShiroService {/*** 初始化權(quán)限 -> 拿全部權(quán)限** @param :* @return: java.util.Map<java.lang.String,java.lang.String>*/Map<String, String> loadFilterChainDefinitionMap();/*** 在對uri權(quán)限進(jìn)行增刪改操作時,需要調(diào)用此方法進(jìn)行動態(tài)刷新加載數(shù)據(jù)庫中的uri權(quán)限** @param shiroFilterFactoryBean* @param roleId* @param isRemoveSession:* @return: void*/void updatePermission(ShiroFilterFactoryBean shiroFilterFactoryBean, String roleId, Boolean isRemoveSession);/*** shiro動態(tài)權(quán)限加載 -> 原理:刪除shiro緩存,重新執(zhí)行doGetAuthorizationInfo方法授權(quán)角色和權(quán)限** @param roleId* @param isRemoveSession:* @return: void*/void updatePermissionByRoleId(String roleId, Boolean isRemoveSession);}

實現(xiàn)類

package com.etouch.config.shiro.service.impl;import com.etouch.config.shiro.service.ShiroService; import com.etouch.entity.SysMenu; import com.etouch.entity.SysUser; import com.etouch.exception.ZhException; import com.etouch.mapper.SysMenuMapper; import com.etouch.mapper.SysRoleMapper; import com.etouch.mapper.SysUserMapper; import com.etouch.utils.ShiroUtils; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.apache.shiro.spring.web.ShiroFilterFactoryBean; import org.apache.shiro.web.filter.mgt.DefaultFilterChainManager; import org.apache.shiro.web.filter.mgt.PathMatchingFilterChainResolver; import org.apache.shiro.web.servlet.AbstractShiroFilter; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.util.CollectionUtils;import java.util.LinkedHashMap; import java.util.List; import java.util.Map;/*** <p> shiro權(quán)限處理實現(xiàn)類 </p>** @description:* @author: zhengqing* @date: 2019/9/7 0007 13:53*/ @Slf4j @Service public class ShiroServiceImpl implements ShiroService {@Autowiredprivate SysMenuMapper menuMapper;@Autowiredprivate SysUserMapper userMapper;@Autowired@Overridepublic Map<String, String> loadFilterChainDefinitionMap() {// 權(quán)限控制mapMap<String, String> filterChainDefinitionMap = new LinkedHashMap<>();// 配置過濾:不會被攔截的鏈接 -> 放行 start ----------------------------------------------------------// 放行Swagger2頁面,需要放行這些filterChainDefinitionMap.put("/swagger-ui.html", "anon");filterChainDefinitionMap.put("/swagger/**", "anon");filterChainDefinitionMap.put("/swagger-resources/**", "anon");filterChainDefinitionMap.put("/static/**", "anon");// 三方登錄 // filterChainDefinitionMap.put("/auth/loginByQQ", "anon"); // filterChainDefinitionMap.put("/auth/afterlogin.do", "anon");// 退出// token過期接口filterChainDefinitionMap.put("/sysUser/tokenExpired", "anon");// 被擠下線filterChainDefinitionMap.put("/sysUser/downline", "anon");//手機號,驗證碼登錄filterChainDefinitionMap.put("/sysUser/login", "anon");filterChainDefinitionMap.put("/sysUser/loginByPhone", "anon");filterChainDefinitionMap.put("/sysUser/logOut", "anon");//管理員可操作所有的//發(fā)送驗證碼和校驗驗證碼filterChainDefinitionMap.put("/*/sendCode", "anon");filterChainDefinitionMap.put("/*/checkoutCode", "anon");//swaggerUI// 放行 end ----------------------------------------------------------//TODO 管理員可以訪問任何接口filterChainDefinitionMap.put("/**", "roles[superAdmin]");// 從數(shù)據(jù)庫或緩存中查取出來的url與resources對應(yīng)則不會被攔截 放行List<SysMenu> permissionList = menuMapper.selectList(null);if (!CollectionUtils.isEmpty(permissionList)) {permissionList.forEach(e -> {if (StringUtils.isNotBlank(e.getMenuUrl())) {filterChainDefinitionMap.put(e.getMenuUrl(), "perms["+e.getMenuUrl()+"]"); // filterChainDefinitionMap.put("/api/system/user/listPage", "authc,token,zqPerms[user1]"); // 寫死的一種用法}});}// ⑤ 認(rèn)證登錄 【注:map不能存放相同key】//TODO 開發(fā)階段不需要登錄就可以訪問filterChainDefinitionMap.put("/**", "anon");return filterChainDefinitionMap;}@Overridepublic void updatePermission(ShiroFilterFactoryBean shiroFilterFactoryBean, String roleId, Boolean isRemoveSession) {synchronized (this) {AbstractShiroFilter shiroFilter;try {shiroFilter = (AbstractShiroFilter) shiroFilterFactoryBean.getObject();} catch (Exception e) {throw new ZhException("get ShiroFilter from shiroFilterFactoryBean error!");}PathMatchingFilterChainResolver filterChainResolver = (PathMatchingFilterChainResolver) shiroFilter.getFilterChainResolver();DefaultFilterChainManager manager = (DefaultFilterChainManager) filterChainResolver.getFilterChainManager();// 清空攔截管理器中的存儲manager.getFilterChains().clear();// 清空攔截工廠中的存儲,如果不清空這里,還會把之前的帶進(jìn)去// ps:如果僅僅是更新的話,可以根據(jù)這里的 map 遍歷數(shù)據(jù)修改,重新整理好權(quán)限再一起添加shiroFilterFactoryBean.getFilterChainDefinitionMap().clear();// 動態(tài)查詢數(shù)據(jù)庫中所有權(quán)限shiroFilterFactoryBean.setFilterChainDefinitionMap(loadFilterChainDefinitionMap());// 重新構(gòu)建生成攔截Map<String, String> chains = shiroFilterFactoryBean.getFilterChainDefinitionMap();for (Map.Entry<String, String> entry : chains.entrySet()) {manager.createChain(entry.getKey(), entry.getValue());}log.info("--------------- 動態(tài)生成url權(quán)限成功! ---------------");// 動態(tài)更新該角色相關(guān)聯(lián)的用戶shiro權(quán)限if (roleId != null) {updatePermissionByRoleId(roleId, isRemoveSession);}}}@Overridepublic void updatePermissionByRoleId(String roleId, Boolean isRemoveSession) {// 查詢當(dāng)前角色的用戶shiro緩存信息 -> 實現(xiàn)動態(tài)權(quán)限List<SysUser> userList = userMapper.selectUserByRoleId(roleId);// 刪除當(dāng)前角色關(guān)聯(lián)的用戶緩存信息,用戶再次訪問接口時會重新授權(quán) ; isRemoveSession為true時刪除Session -> 即強制用戶退出if (!CollectionUtils.isEmpty(userList)) {for (SysUser user : userList) {ShiroUtils.deleteCache(user.getLoginName(), isRemoveSession);}}log.info("--------------- 動態(tài)修改用戶權(quán)限成功! ---------------");}}

5. 新建shiro的配置文件ShiroConfig

package com.etouch.config.shiro;import java.util.ArrayList; import java.util.List;import com.etouch.utils.CustomCredentialsMatcher; import com.etouch.config.shiro.service.impl.ShiroServiceImpl; import org.apache.shiro.codec.Base64; import org.apache.shiro.mgt.SecurityManager; import org.apache.shiro.realm.Realm; import org.apache.shiro.session.mgt.SessionManager; import org.apache.shiro.spring.LifecycleBeanPostProcessor; import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor; import org.apache.shiro.spring.web.ShiroFilterFactoryBean; import org.apache.shiro.web.mgt.CookieRememberMeManager; import org.apache.shiro.web.mgt.DefaultWebSecurityManager; import org.apache.shiro.web.servlet.SimpleCookie; import org.crazycake.shiro.RedisCacheManager; import org.crazycake.shiro.RedisManager; import org.crazycake.shiro.RedisSessionDAO; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration;@Configuration public class ShiroConfig {private final String CACHE_KEY = "shiro:cache:";private final String SESSION_KEY = "shiro:session:";private final int EXPIRE = 1000*60*60*24*7; //TODO 單位毫秒/*** Redis配置*/@Value("${spring.redis.host}")private String host;@Value("${spring.redis.port}")private int port;@Value("${spring.redis.timeout}")private int timeout;@Value("${shiro.session.jsessionid}")private String jsessionid;@Beanpublic ShiroFilterFactoryBean shirFilter(SecurityManager securityManager, ShiroServiceImpl shiroService) {ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();shiroFilterFactoryBean.setSecurityManager(securityManager);/** 常用的過濾器如下:authc:所有已登陸用戶可訪問roles:有指定角色的用戶可訪問,通過[ ]指定具體角色,這里的角色名稱與數(shù)據(jù)庫中配置一致perms:有指定權(quán)限的用戶可訪問,通過[ ]指定具體權(quán)限,這里的權(quán)限名稱與數(shù)據(jù)庫中配置一致anon:所有用戶可訪問,通常作為指定頁面的靜態(tài)資源時使用* *///未登錄提示shiroFilterFactoryBean.setLoginUrl("/sysUser/unLogin");//沒有權(quán)限提示shiroFilterFactoryBean.setUnauthorizedUrl("/sysUser/unAuth");// 權(quán)限控制map.shiroFilterFactoryBean.setFilterChainDefinitionMap(shiroService.loadFilterChainDefinitionMap());return shiroFilterFactoryBean;}@Beanpublic CustomCredentialsMatcher credentialMatcher() {return new CustomCredentialsMatcher();}// 將自己的驗證方式加入容器,注入自定義的realm@Beanpublic MyShiroRealm myShiroRealm() {MyShiroRealm myShiroRealm = new MyShiroRealm();//將密碼比較器注入自定義realm域myShiroRealm.setCredentialsMatcher(credentialMatcher());myShiroRealm.setCacheManager(cacheManager());return myShiroRealm;}@Beanpublic PhoneRealm phoneRealm() {PhoneRealm phoneRealm = new PhoneRealm();phoneRealm.setCacheManager(cacheManager());return phoneRealm;}// 權(quán)限管理,配置主要是Realm的管理認(rèn)證/*** 配置核心安全事務(wù)管理器** @param shiroRealm* @return*/@Bean(name = "securityManager")public SecurityManager securityManager(@Qualifier("myShiroRealm") MyShiroRealm shiroRealm, PhoneRealm phoneRealm) {DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();// 設(shè)置realmsList<Realm> realms = new ArrayList<>();realms.add(shiroRealm);realms.add(phoneRealm);//設(shè)置自定義realm.securityManager.setRealms(realms);//配置記住我securityManager.setRememberMeManager(rememberMeManager());// 自定義session管理securityManager.setSessionManager(sessionManager());// 自定義Cache實現(xiàn)緩存管理securityManager.setCacheManager(cacheManager());return securityManager;}/*** cookie對象;會話Cookie模板 ,默認(rèn)為: JSESSIONID 問題: 與SERVLET容器名沖突,重新定義為sid或rememberMe,自定義** @return*/@Beanpublic SimpleCookie rememberMeCookie() {//這個參數(shù)是cookie的名稱,對應(yīng)前端的checkbox的name = rememberMeSimpleCookie simpleCookie = new SimpleCookie("rememberMe");//setcookie的httponly屬性如果設(shè)為true的話,會增加對xss防護(hù)的安全系數(shù)。它有以下特點://setcookie()的第七個參數(shù)//設(shè)為true后,只能通過http訪問,javascript無法訪問//防止xss讀取cookiesimpleCookie.setHttpOnly(true);simpleCookie.setPath("/");//<!-- 記住我cookie生效時間30天 ,單位秒;-->simpleCookie.setMaxAge(2592000);return simpleCookie;}/*** cookie管理對象;記住我功能,rememberMe管理器** @return*/@Beanpublic CookieRememberMeManager rememberMeManager() {CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();cookieRememberMeManager.setCookie(rememberMeCookie());//rememberMe cookie加密的密鑰 建議每個項目都不一樣 默認(rèn)AES算法 密鑰長度(128 256 512 位)cookieRememberMeManager.setCipherKey(Base64.decode("4AvVhmFLUs0KTA3Kprsdag=="));return cookieRememberMeManager;}// 加入注解的使用,不加入這個注解不生效@Beanpublic AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);return authorizationAttributeSourceAdvisor;}/*** 配置Redis管理器:使用的是shiro-redis開源插件*/@Beanpublic RedisManager redisManager() {RedisManager redisManager = new RedisManager();redisManager.setHost(host);redisManager.setPort(port);redisManager.setTimeout(timeout); // redisManager.setPassword(password);return redisManager;}/*** 配置Cache管理器:用于往Redis存儲權(quán)限和角色標(biāo)識 (使用的是shiro-redis開源插件)*/@Beanpublic RedisCacheManager cacheManager() {RedisCacheManager redisCacheManager = new RedisCacheManager();redisCacheManager.setRedisManager(redisManager());redisCacheManager.setKeyPrefix(CACHE_KEY);// 配置緩存的話要求放在session里面的實體類必須有個id標(biāo)識 注:這里id為用戶表中的主鍵,否-> 報:User must has getter for field: xxredisCacheManager.setPrincipalIdFieldName("id");return redisCacheManager;}/*** SessionID生成器*/@Beanpublic ShiroSessionIdGenerator sessionIdGenerator() {return new ShiroSessionIdGenerator();}/*** 配置RedisSessionDAO (使用的是shiro-redis開源插件)*/@Beanpublic RedisSessionDAO redisSessionDAO() {RedisSessionDAO redisSessionDAO = new RedisSessionDAO();redisSessionDAO.setRedisManager(redisManager());redisSessionDAO.setSessionIdGenerator(sessionIdGenerator());redisSessionDAO.setKeyPrefix(SESSION_KEY);redisSessionDAO.setExpire(EXPIRE);return redisSessionDAO;}/*** 配置Session管理器*/@Beanpublic SessionManager sessionManager() {ShiroSessionManager shiroSessionManager = new ShiroSessionManager();shiroSessionManager.setGlobalSessionTimeout(EXPIRE);shiroSessionManager.setSessionDAO(redisSessionDAO());//修改默認(rèn)session存儲機制,將shiro中的session數(shù)據(jù)存儲至redis數(shù)據(jù)庫中shiroSessionManager.setSessionIdCookie(getSessionIdCookie());//設(shè)置sessionId的KeyshiroSessionManager.setDeleteInvalidSessions(true);//自動清空失效sessionreturn shiroSessionManager;}/*** 給shiro的sessionId默認(rèn)的JSSESSIONID名字改掉* @return*/@Bean(name="sessionIdCookie")public SimpleCookie getSessionIdCookie(){SimpleCookie simpleCookie = new SimpleCookie(jsessionid);return simpleCookie;}/*** 該類如果不設(shè)置為static,@Value注解就無效,原因未知* @return*/@Beanpublic static LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {return new LifecycleBeanPostProcessor();}}

自定義密碼比較器

package com.etouch.utils;import com.etouch.corecenter.utils.MD5Util; import com.etouch.utils.Encrypt; import org.apache.shiro.authc.AuthenticationInfo; import org.apache.shiro.authc.AuthenticationToken; import org.apache.shiro.authc.UsernamePasswordToken; import org.apache.shiro.authc.credential.CredentialsMatcher;public class CustomCredentialsMatcher implements CredentialsMatcher {/**** @param token 用戶輸入的用戶名和密碼* @param info 數(shù)據(jù)庫中的用戶名和密碼* @return 返回如果是false 則登錄失敗, 返回true 則登錄成功*/@Overridepublic boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {/*** 驗證數(shù)據(jù)庫的密碼 和 用戶輸入的密碼 是否一致** @param token 用戶輸入的用戶名 密碼* @param info 數(shù)據(jù)庫中的用戶名 密碼* @return 返回值 比較密碼是否正確 比較正確 返回true 表示登陸成功 返回false 表示登陸失敗(同時拋出異常)** 明文密碼: 不加密 原始密碼* 密文密碼: 經(jīng)過一定的加密處理 , 數(shù)據(jù)更加安全* md5加密 : 不可逆的加密方式* 先將加密后的數(shù)據(jù) 以及加密前的數(shù)據(jù) 提前保存了 根據(jù)對應(yīng)的數(shù)據(jù)找即可* 123456 -> xxxxyyyyqqqq** 如何屏蔽這種情況* 123456 -> xxxxyyyyqqqq* 123456000 -> asdasdfg* 用戶輸入的密碼 + 固定值(不變的值) = 特殊的密碼* 用戶輸入的密碼 + 可變化的固定值 = 特殊的密碼* password:123456 + 用戶的登錄名 = 特殊的密碼* 加密: 直接轉(zhuǎn)換* 加鹽加密: 在原有的密碼基礎(chǔ)上 加上一定的參數(shù) 針對該用戶而言 這個鹽(新加入的參數(shù)) 是不變的*/// System.out.println("密碼比較器執(zhí)行"); // //加鹽加密 // UsernamePasswordToken upToken = (UsernamePasswordToken) token; // //獲取用戶輸入的數(shù)據(jù) // String email = upToken.getUsername(); // String password = new String(upToken.getPassword()); // //對密碼進(jìn)行加密處理 加鹽加密 // String md5Pwd = Encrypt.md5(password, email); // //獲得數(shù)據(jù)庫的密碼 // String dbPwd = (String) info.getCredentials(); // return md5Pwd.equals(dbPwd);//不加鹽加密UsernamePasswordToken upToken = (UsernamePasswordToken) token;//獲得用戶輸入的密碼String password = new String(upToken.getPassword());//加密后的密碼String md5Pwd = MD5Util.string2MD5(password);//獲取數(shù)據(jù)庫的密碼String dbPwd = (String) info.getCredentials();return md5Pwd.equals(dbPwd);} } ### 6. 新建shiro的session管理器```javapackage com.etouch.config.shiro;import com.etouch.utils.constants.Constants; import org.apache.commons.lang3.StringUtils; import org.apache.shiro.web.servlet.ShiroHttpServletRequest; import org.apache.shiro.web.session.mgt.DefaultWebSessionManager; import org.apache.shiro.web.util.WebUtils;import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import java.io.Serializable;import static org.apache.shiro.web.servlet.ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE;/*** <p> 自定義獲取Token </p>** @description :* @author : zhengqing* @date : 2019/8/23 15:55*/ public class ShiroSessionManager extends DefaultWebSessionManager {/*** 定義常量*/ // private static final String REFERENCED_SESSION_ID_SOURCE = "Stateless request";/*** 重寫構(gòu)造器*/public ShiroSessionManager() {super();this.setDeleteInvalidSessions(true);}/*** 重寫方法實現(xiàn)從請求頭獲取Token便于接口統(tǒng)一* 每次請求進(jìn)來,Shiro會去從請求頭找REQUEST_HEADER這個key對應(yīng)的Value(Token)*/@Overridepublic Serializable getSessionId(ServletRequest request, ServletResponse response) {String token = WebUtils.toHttp(request).getHeader(Constants.REQUEST_HEADER);// 如果請求頭中存在token 則從請求頭中獲取tokenif ( StringUtils.isNotBlank( token ) ) {request.setAttribute(REFERENCED_SESSION_ID_SOURCE, REFERENCED_SESSION_ID_SOURCE);request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID, token);request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_IS_VALID, Boolean.TRUE);return token;} else {// 否則按默認(rèn)規(guī)則從cookie取tokenreturn super.getSessionId(request, response);}} }

7. 用戶名密碼登陸

/*** 用戶名密碼登錄** @param userName* @param passWord* @param rememberMe* @return*/@ApiOperation(value = "用戶名密碼登錄", notes = "用戶名密碼登錄")@PostMapping("/login")public ResultUtils<String> login(HttpServletRequest request,@ApiParam(value = "用戶名", required = true) @RequestParam(name = "userName") String userName,@ApiParam(value = "密碼", required = true) @RequestParam(name = "passWord") String passWord,@ApiParam("記住密碼,true,false") @RequestParam(name = "rememberMe") boolean rememberMe,@ApiParam("驗證碼") @RequestParam(name = "VerificationCode") String VerificationCode) {if (StringUtils.isBlank(userName) || StringUtils.isBlank(passWord)) {return ResultUtils.error("用戶名或密碼不能為空");}if (checkVerify(request, VerificationCode).getCode() != 200) {return ResultUtils.errorParam("驗證碼錯誤,請重新輸入");}QueryWrapper<SysUser> queryWrapper = new QueryWrapper();queryWrapper.eq("login_name", userName);SysUser sysUser = sysUserService.getOne(queryWrapper);if (sysUser == null) {return ResultUtils.error("用戶名不存在");}String encodePwd = MD5Util.string2MD5(passWord);log.info("加密碼后的密碼為: " + encodePwd);if (!encodePwd.equals(sysUser.getPassword())) {return ResultUtils.error("用戶名或密碼錯誤");}//登錄前,先清除掉之前的用戶登錄信息this.shiroCheck();UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(userName, passWord, rememberMe);//登錄操作Subject subject = SecurityUtils.getSubject();LoginUser loginUser = new LoginUser();//存入用戶id和tokenString uToken = null;try {//進(jìn)行shiro登錄驗證subject.login(usernamePasswordToken);uToken = ShiroUtils.getSession().getId().toString();//subject.getSession().setAttribute("loginUser", sysUser);//userService.login(sysUser, rememberMe, uToken);SecurityUtils.getSubject().getSession().setTimeout(1000*60*60*24*7);return ResultUtils.success("登陸成功", uToken);} catch (AuthenticationException e) {e.printStackTrace();return ResultUtils.error("登錄失敗");} catch (InvalidSessionException e) {e.printStackTrace();return ResultUtils.error("登錄失敗");}}

8 如需增加手機號, 驗證碼登陸, 則需進(jìn)行以下配置

8.1重寫shiro的token獲取類

package com.etouch.config.shiro;import org.apache.shiro.authc.HostAuthenticationToken; import org.apache.shiro.authc.RememberMeAuthenticationToken;import java.io.Serializable;public class UserNamePasswordPhoneToken implements HostAuthenticationToken, RememberMeAuthenticationToken, Serializable {// 手機號碼private String phone;private boolean rememberMe;private String host;/*** 重寫getPrincipal方法*/public Object getPrincipal() {return phone;}/*** 重寫getCredentials方法*/public Object getCredentials() {return phone;}public UserNamePasswordPhoneToken() {this.rememberMe = false;}public UserNamePasswordPhoneToken(String phone) {this(phone, false, null);}public UserNamePasswordPhoneToken(String phone, boolean rememberMe) {this(phone, rememberMe, null);}public UserNamePasswordPhoneToken(String phone, boolean rememberMe, String host) {this.phone = phone;this.rememberMe = rememberMe;this.host = host;}public String getPhone() {return phone;}public void setPhone(String phone) {this.phone = phone;}@Overridepublic String getHost() {return host;}@Overridepublic boolean isRememberMe() {return rememberMe;} }

8.2 新建PhoneRealm 繼承AuthorizingRealm

package com.etouch.config.shiro;import com.etouch.DTO.MenuDTO; import com.etouch.DTO.RoleDTO; import com.etouch.DTO.UserDTO; import com.etouch.entity.SysUser; import com.etouch.DTO.search.SearchUserArgs; import com.etouch.service.UserService; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authc.AuthenticationInfo; import org.apache.shiro.authc.AuthenticationToken; import org.apache.shiro.authc.SimpleAuthenticationInfo; import org.apache.shiro.authz.AuthorizationInfo; import org.apache.shiro.authz.SimpleAuthorizationInfo; import org.apache.shiro.realm.AuthorizingRealm; import org.apache.shiro.subject.PrincipalCollection; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired;public class PhoneRealm extends AuthorizingRealm {@Autowiredprivate UserService userService;// 登錄認(rèn)證@Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {UserNamePasswordPhoneToken token = null;// 如果是PhoneToken,則強轉(zhuǎn),獲取phone;否則不處理。if (authenticationToken instanceof UserNamePasswordPhoneToken) {token = (UserNamePasswordPhoneToken) authenticationToken;} else {return null;}String phone = (String) token.getPrincipal();SearchUserArgs searchUserArgs = new SearchUserArgs();if (phone.contains("@")) {searchUserArgs.setEmail(phone);} else {searchUserArgs.setPhone(phone);}SysUser user = userService.findByArgs(searchUserArgs);UserDTO userDTO = new UserDTO();BeanUtils.copyProperties(user,userDTO);if (userDTO == null) {throw null;}return new SimpleAuthenticationInfo(userDTO, phone, this.getName());}/*** 權(quán)限校驗* @param principalCollection* @return*/@Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();UserDTO user = (UserDTO) SecurityUtils.getSubject().getPrincipal();UserDTO userDTO = userService.findUserByName(user.getLoginName());for (RoleDTO role : userDTO.getRoleList()) {authorizationInfo.addRole(role.getRoleName());for (MenuDTO menu : role.getMenuDTOList()) {authorizationInfo.addStringPermission(menu.getMenuUrl());}}return authorizationInfo;}@Overridepublic boolean supports(AuthenticationToken var1) {return var1 instanceof UserNamePasswordPhoneToken;}}

8.3 新增手機號驗證碼登陸

@ApiOperation("手機號,驗證碼登錄")@PostMapping("/loginByPhone")public ResultUtils<String> login(@ApiParam("手機號") @RequestParam(name = "phone") String phone,@ApiParam("驗證碼") @RequestParam(name = "code") String code, @ApiParam("記住密碼") Boolean rememberMe) {//首先校驗驗證碼Boolean b = userService.checkoutCode(phone, code);if (!b) {return ResultUtils.errorParam("驗證碼錯誤,請重新輸入");}QueryWrapper<SysUser> queryWrapper = new QueryWrapper<>();//通過手機號或者與郵箱賬號查詢用戶SearchUserArgs searchUserArgs = new SearchUserArgs();if (phone.contains("@")) {searchUserArgs.setEmail(phone);} else {searchUserArgs.setPhone(phone);}SysUser sysUser = userService.findByArgs(searchUserArgs);if (sysUser == null) {return ResultUtils.errorParam("查找不到用戶信息");}this.shiroCheck();//清除掉這臺客戶端的上個用戶的登錄信息UserNamePasswordPhoneToken userNamePasswordPhoneToken = new UserNamePasswordPhoneToken(phone);//登錄操作Subject subject = SecurityUtils.getSubject();LoginUser loginUser = new LoginUser();//存入用戶id和tokenString uToken = null;try {//進(jìn)行shiro登錄驗證uToken = ShiroUtils.getSession().getId().toString();subject.login(userNamePasswordPhoneToken);userService.login(sysUser, rememberMe, uToken);return ResultUtils.success("登陸成功", uToken);} catch (AuthenticationException e) {e.printStackTrace();return ResultUtils.error("登錄失敗");} catch (InvalidSessionException e) {e.printStackTrace();return ResultUtils.error("登錄失敗");}}

ShiroUtils工具類

package com.etouch.utils;import com.etouch.DTO.UserDTO; import com.etouch.corecenter.enums.ExceptionEnum; import com.etouch.corecenter.exception.ProjectExeption; import com.etouch.entity.SysUser; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.Authenticator; import org.apache.shiro.authc.LogoutAware; import org.apache.shiro.session.Session; import org.apache.shiro.subject.SimplePrincipalCollection; import org.apache.shiro.subject.support.DefaultSubjectContext; import org.apache.shiro.web.mgt.DefaultWebSecurityManager; import org.crazycake.shiro.RedisSessionDAO;import java.util.Collection; import java.util.Objects;/*** <p> Shiro工具類 </p>*/ public class ShiroUtils {/*** 私有構(gòu)造器**/private ShiroUtils() {}private static RedisSessionDAO redisSessionDAO = SpringUtil.getBean(RedisSessionDAO.class);// public static final String LOGIN_USER_IN_SESSION = "loginUser";/*** 傳入一個用戶放到session中* @param user*/ // public static void setUserInfo(User user){ // Session session = getSession(); // // 將用戶信息放到session中 // session.setAttribute(LOGIN_USER_IN_SESSION, user); // }/*** 從session中獲取一個用戶的信息*/ // public static User getUser(){ // Session session = getSession(); // return (User) session.getAttribute(LOGIN_USER_IN_SESSION); // }// -------------------------------------------------------------/*** 獲取當(dāng)前用戶Session** @Return SysUserEntity 用戶信息*/public static Session getSession() {return SecurityUtils.getSubject().getSession();}/*** 用戶登出*/public static void logout() {SecurityUtils.getSubject().logout();}/*** 獲取當(dāng)前用戶信息** @Return SysUserEntity 用戶信息*/public static UserDTO getUserInfo() {return (UserDTO) SecurityUtils.getSubject().getPrincipal();}/*** 獲取當(dāng)前登陸用戶id** @Return*/public static String getLoginUserId() {UserDTO userDTO = (UserDTO) SecurityUtils.getSubject().getPrincipal();if (userDTO == null) {throw new ProjectExeption(ExceptionEnum.UNLOGIN);}return userDTO.getId();}/*** 刪除用戶緩存信息** @Param username 用戶名稱* @Param isRemoveSession 是否刪除Session,刪除后用戶需重新登錄*/public static void deleteCache(String username, boolean isRemoveSession) {//從緩存中獲取SessionSession session = null;// 獲取當(dāng)前已登錄的用戶session列表Collection<Session> sessions = redisSessionDAO.getActiveSessions();UserDTO sysUserEntity;Object attribute = null;// 遍歷Session,找到該用戶名稱對應(yīng)的Sessionfor (Session sessionInfo : sessions) {attribute = sessionInfo.getAttribute(DefaultSubjectContext.PRINCIPALS_SESSION_KEY);if (attribute == null) {continue;}sysUserEntity = (UserDTO) ((SimplePrincipalCollection) attribute).getPrimaryPrincipal();if (sysUserEntity == null) {continue;}if (Objects.equals(sysUserEntity.getLoginName(), username)) {session = sessionInfo;// 清除該用戶以前登錄時保存的session,強制退出 -> 單用戶登錄處理if (isRemoveSession) {redisSessionDAO.delete(session);}}}if (session == null || attribute == null) {return;}//刪除sessionif (isRemoveSession) {redisSessionDAO.delete(session);}//刪除Cache,再訪問受限接口時會重新授權(quán)DefaultWebSecurityManager securityManager = (DefaultWebSecurityManager) SecurityUtils.getSecurityManager();Authenticator authc = securityManager.getAuthenticator();((LogoutAware) authc).onLogout((SimplePrincipalCollection) attribute);}/*** 從緩存中獲取指定用戶名的Session** @param username*/private static Session getSessionByUsername(String username) {// 獲取當(dāng)前已登錄的用戶session列表Collection<Session> sessions = redisSessionDAO.getActiveSessions();SysUser user;Object attribute;// 遍歷Session,找到該用戶名稱對應(yīng)的Sessionfor (Session session : sessions) {attribute = session.getAttribute(DefaultSubjectContext.PRINCIPALS_SESSION_KEY);if (attribute == null) {continue;}user = (SysUser) ((SimplePrincipalCollection) attribute).getPrimaryPrincipal();if (user == null) {continue;}if (Objects.equals(user.getLoginName(), username)) {return session;}}return null;}}

}

總結(jié)

以上是生活随笔為你收集整理的spring boot结合shiro实现用户-角色-权限的控制(包含用户名密码登陆和手机号验证码登陆)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

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

人人澡超碰碰97碰碰碰软件 | 日韩免费在线观看视频 | 久久图 | 狠狠操欧美| 婷婷在线播放 | 精品在线观看国产 | 欧美aaa大片 | 欧美日韩三区二区 | 婷婷激情综合五月天 | 中文视频一区二区 | 81精品国产乱码久久久久久 | 激情电影影院 | 国产91勾搭技师精品 | 午夜性福利 | 久色小说| 国产免费黄视频在线观看 | 亚洲综合激情小说 | 五月婷婷开心 | 久草在线视频首页 | 黄色日本免费 | 久久高清av | 日韩av不卡在线播放 | 在线观看一 | 亚洲爱爱视频 | 91精品爽啪蜜夜国产在线播放 | 正在播放国产一区 | 国产精品免费在线播放 | 日韩精品不卡 | 国产亚洲欧美精品久久久久久 | 不卡电影免费在线播放一区 | 狠狠色网 | 午夜丁香网 | 午夜影院三级 | 91精品久久久久久久久久入口 | 99热这里只有精品免费 | av片在线观看免费 | 91人人爽久久涩噜噜噜 | 国内揄拍国产精品 | 国产一级做a爱片久久毛片a | 亚洲精品在 | 超碰97中文 | 成人毛片在线视频 | 免费v片 | 天天干天天干天天干天天干天天干天天干 | 一区 二区电影免费在线观看 | www一起操 | 亚洲理论视频 | 国产在线视频一区 | 日本公乱妇视频 | 97在线观看免费高清 | 国产高清专区 | 又污又黄的网站 | 国产精品美| 日韩欧美视频一区二区三区 | 成人午夜影院在线观看 | 深爱激情开心 | 亚洲黄色av网址 | 国产成人久久 | 欧美在线观看视频 | 亚洲精品国偷拍自产在线观看蜜桃 | 亚洲婷婷在线视频 | 久久精品久久精品久久39 | 国产精品午夜免费福利视频 | 精品欧美一区二区在线观看 | 久操伊人 | 国产香蕉久久精品综合网 | 日韩在线一二三区 | 色综合亚洲精品激情狠狠 | 久久久久久久久久久影院 | 日日碰狠狠添天天爽超碰97久久 | 岛国av在线 | 国产日韩一区在线 | 2023av| 久久免费在线观看视频 | 91久久精品一区 | 91成人天堂久久成人 | 久久久免费精品 | 欧美色操 | 91亚洲综合 | 成人午夜电影在线观看 | 免费在线成人av | zzijzzij亚洲成熟少妇 | 午夜久久久精品 | 国产精品久久久久国产a级 激情综合中文娱乐网 | 久久99精品久久久久蜜臀 | 天天色天天干天天 | 亚洲男人天堂a | 国产成人a v电影 | 97超级碰 | 99国产视频在线 | 插插插色综合 | 久久国产精品一区二区三区四区 | 香蕉视频在线看 | 久久成人免费电影 | 黄色大片av| 亚洲毛片视频 | 国产91在线免费视频 | 一本一本久久aa综合精品 | 日韩在线免费 | 干 操 插| 天天操天天能 | 久久精品欧美一区二区三区麻豆 | 中文字幕刺激在线 | 国产一级片免费播放 | 免费a v视频| 在线观看黄网 | 欧美一级电影在线观看 | 亚洲欧美视频在线观看 | 一区二区三区在线观看免费视频 | 美女在线免费视频 | 最近日本韩国中文字幕 | 日韩在线 | 经典三级一区 | 免费亚洲一区二区 | 久久久久久久久久久免费 | 看黄色91 | 成人a在线观看高清电影 | 欧美日本一区 | 日韩欧美一区二区三区免费观看 | 在线观看av免费观看 | 精品久久久久久综合 | 99久久久久久久久久 | 亚洲午夜精品一区二区三区电影院 | 久久精品中文字幕免费mv | av中文字幕亚洲 | 国内精品久久久久影院男同志 | 亚州欧美精品 | 激情深爱五月 | 国精产品999国精产 久久久久 | 色五丁香 | 精品视频999 | 久久手机在线视频 | 一本一道久久a久久精品蜜桃 | 色噜噜狠狠狠狠色综合久不 | 久久久久久久久久电影 | 国产免费观看久久 | 日韩av网页 | 99国产成+人+综合+亚洲 欧美 | 日韩一级精品 | 伊人五月天.com | 黄在线免费观看 | 午夜精品福利一区二区三区蜜桃 | 国产精品久久久一区二区三区网站 | 少妇搡bbb| 美女黄久久| 欧美另类网站 | 最新日本中文字幕 | 爱爱一区| 日韩免费网址 | 欧美在线观看视频免费 | 国产精品永久免费在线 | 免费视频一区 | 91热这里只有精品 | 天天操天天干天天干 | 91探花国产综合在线精品 | 欧美成人tv | 在线 影视 一区 | 精品一区二区在线看 | 夜又临在线观看 | 精品国产伦一区二区三区观看方式 | 精选久久 | 97视频在线看 | 久久99国产一区二区三区 | 国产在线观看地址 | 欧美精品久久久久久久久久久 | 亚洲三级影院 | 久久99热这里只有精品国产 | 成年人免费在线观看 | 久久五月婷婷丁香 | 91麻豆精品国产91久久久无需广告 | 亚洲欧美综合 | 国产三级久久久 | 在线观看韩日电影免费 | 日韩久久网站 | 在线观看国产日韩 | 色 免费观看 | 在线播放视频一区 | 久久视频免费观看 | 日韩视频一 | 手机av永久免费 | 久久久精品 | 国内精品久久久久久久久久久 | 九七视频在线 | 中文乱码视频在线观看 | 日韩精品中文字幕在线观看 | 国产一级免费视频 | 精品免费久久久久 | 欧美性受极品xxxx喷水 | 91国内在线视频 | 99免费在线视频观看 | 国产成人在线观看 | 日韩精品偷拍 | 亚洲精品国产综合久久 | 成人av午夜 | 五月天欧美精品 | 在线视频观看亚洲 | 欧美日性视频 | 操高跟美女| 日日摸日日添夜夜爽97 | 久久久电影网站 | 久久久在线免费观看 | 久久久久久久久久久综合 | 国产一区免费在线观看 | 国产破处在线视频 | 久久国产精品99久久久久久进口 | 欧美日韩在线精品 | 97人人人人 | 人人舔人人射 | 深夜免费福利 | 波多野结衣网址 | 久久影院一区 | 亚洲国产成人在线 | 91成年视频| 免费a视频在线观看 | 在线亚洲成人 | 天堂va欧美va亚洲va老司机 | 精品久久精品久久 | 免费在线国产视频 | 国产高清av | 欧美精品久久久久久久亚洲调教 | 97国产在线观看 | 91人人爱 | 日韩免费看视频 | 91视频在线国产 | 中文字幕色在线视频 | 久久久久久片 | 香蕉国产91| 日韩精品在线看 | 色视频在线观看 | 亚洲天天 | 国产流白浆高潮在线观看 | 亚洲 欧美 精品 | 99久久久国产精品免费99 | 久久久久成人免费 | 婷香五月 | 四虎最新入口 | 欧美91精品国产自产 | 久久久国产影视 | 韩日精品视频 | 97超碰资源 | 国产亚洲激情视频在线 | 91精品久久久久 | 美女网站在线播放 | 欧美日韩高清国产 | 在线91网 | 人人射av | 久草精品视频在线播放 | 欧美日韩国产精品一区二区亚洲 | 国产爽视频 | 美女视频黄是免费的 | 色婷婷亚洲综合 | 久久久久久久久久电影 | av片免费播放 | 国产精品igao视频网入口 | 国产高清99 | 奇米四色影狠狠爱7777 | 狠狠狠色丁香综合久久天下网 | 成人av中文字幕 | 国产精品剧情在线亚洲 | 国产精品大片 | 国产很黄很色的视频 | 国产精品午夜久久久久久99热 | 国产一区二区三区四区在线 | 日韩精品一区二区三区在线播放 | 三级av网站 | 国产精品久99 | 国产96av| 国产做aⅴ在线视频播放 | 国产网红在线 | 欧美 激情在线 | 久久久久免费看 | 国产成人精品999 | 免费三及片 | 天天看天天干 | 天天干天天干天天干天天干天天干天天干 | av先锋影音少妇 | 93久久精品日日躁夜夜躁欧美 | 91久久影院| 免费欧美精品 | 久久黄色免费 | 视频一区久久 | av黄在线播放 | 黄色网址av| av大片网站| 久久成年人网站 | 免费视频91| 国产一二区在线观看 | 一本一道波多野毛片中文在线 | 九九在线视频免费观看 | 亚洲无吗天堂 | 国产精品一区在线播放 | 日日夜精品 | 波多野结衣视频一区 | 欧美最新另类人妖 | 国产精品一区电影 | 色婷在线 | 午夜aaaa| 国产在线小视频 | 国产亚洲精品av | 日韩毛片精品 | 天天操天天干天天操天天干 | 久草在线99| 亚洲视屏在线播放 | 久久久久久久久久免费 | 精品国产一区二区三区四 | 国产91粉嫩白浆在线观看 | 在线免费色 | 在线中文字幕一区二区 | 日本精品一区二区三区在线播放视频 | 91资源在线视频 | 夜夜澡人模人人添人人看 | 亚洲国产精品传媒在线观看 | 天天射天天干天天插 | 激情婷婷亚洲 | 久久久精品久久日韩一区综合 | 1024手机基地在线观看 | 国产三级av在线 | 97视频网址 | 精品视频在线看 | 久久免费视频1 | 91视频在线播放视频 | 日韩专区av | av大全免费在线观看 | 国产精品原创av片国产免费 | 成人综合婷婷国产精品久久免费 | www.久久久 | 国产成人久久精品77777 | 97视频在线免费播放 | 国产视频在线一区二区 | 特级黄色视频毛片 | 91亚色免费视频 | 婷婷丁香激情网 | 国产免费亚洲 | av黄色免费网站 | 在线亚洲成人 | 99久久精品免费看国产 | 成人久久电影 | 在线免费色视频 | 日韩在线三区 | 婷婷四房综合激情五月 | 99亚洲国产 | 狠狠狠狠狠狠狠干 | av在线网站观看 | 国产午夜精品一区二区三区 | 久久久久亚洲精品成人网小说 | 天天操天天舔天天爽 | 四虎在线影视 | 黄色国产在线观看 | 五月天免费网站 | 亚洲精品小视频 | 亚洲作爱 | 亚洲天天干 | 久久久国产精品亚洲一区 | 亚洲精品国产精品国自产 | www.国产高清 | 国产精品黄网站在线观看 | 国产精品成久久久久 | 91pony九色丨交换 | 99爱在线| 国产精品毛片一区视频播 | 成人免费影院 | 免费三级骚 | 美腿丝袜一区二区三区 | 久久久久久久久久久久影院 | 精品久久久999 | 日本不卡123| 亚洲国产资源 | 欧美a在线免费观看 | 久久久久久久99精品免费观看 | 久久精品久久精品久久39 | www.亚洲精品视频 | 日韩精品一区二区三区不卡 | 欧美另类tv| 精品国产伦一区二区三区观看体验 | 91福利视频网站 | 日韩在线观看第一页 | www日韩在线 | 福利一区在线视频 | 久久久久| 夜色资源站wwwcom | 国产精品乱码一区二三区 | 日韩免费av在线 | 成人黄色电影在线观看 | 亚洲一二视频 | 在线观看深夜视频 | 久久精品国产免费 | 亚洲理论电影网 | 国产精品一区久久久久 | 欧美一区二区在线刺激视频 | 狠狠狠色| 国产亚洲精品综合一区91 | 992tv人人网tv亚洲精品 | 天堂成人在线 | 九色精品免费永久在线 | 精品久久久久免费极品大片 | 亚洲视屏 | 国产色视频一区二区三区qq号 | 国产成人综合精品 | 在线观看久久久久久 | 精品一区中文字幕 | 亚洲精品视频网站在线观看 | 免费看黄色大全 | 日韩欧美网址 | 国产精品淫片 | 成人午夜精品 | 免费涩涩网站 | 日韩精品一区二区三区外面 | 91麻豆网站| 国产在线91在线电影 | 国内精品久久久精品电影院 | 国产五月婷 | 亚洲一区网 | 久久99精品久久久久久秒播蜜臀 | 美女一二三区 | 99九九热只有国产精品 | 天天玩天天干 | 国内精品久久久久久久久久清纯 | 一区二区三区日韩视频在线观看 | 久久国产精品网站 | 亚洲 中文 欧美 日韩vr 在线 | 九九热在线观看视频 | 国产中文字幕在线视频 | 午夜精品电影一区二区在线 | 又大又硬又黄又爽视频在线观看 | 国产精品成人免费精品自在线观看 | 91视视频在线直接观看在线看网页在线看 | 久久噜噜少妇网站 | 国产成人61精品免费看片 | 国产一二区在线观看 | 久久综合免费视频影院 | 99视频在线精品国自产拍免费观看 | 亚洲人精品午夜 | 日日爱视频 | 国产一级电影在线 | 久久艹国产| 亚洲免费黄色 | 操久| 91九色在线观看视频 | 日韩毛片在线一区二区毛片 | 久9在线 | 国产精品一区二区三区免费看 | 成年人视频免费在线播放 | 在线99 | 国产精品久久久久久久99 | 久一网站 | 青青河边草免费直播 | 国产精品18久久久 | 国产91在线观看 | 免费中午字幕无吗 | 综合网色 | 亚洲国产日韩欧美在线 | 伊人超碰在线 | 99久久国产免费免费 | 国产精品成人一区二区 | 亚洲女人天堂成人av在线 | av电影亚洲 | 狠狠色免费 | 91香蕉视频色版 | 免费观看国产成人 | 午夜精品久久久久久久99 | 国内三级在线观看 | 精品亚洲一区二区 | 91九色丨porny丨丰满6 | 麻豆精品视频在线 | 欧美一区日韩精品 | 偷拍久久久 | 免费福利在线观看 | 久草在线最新免费 | 色网站中文字幕 | 91视频这里只有精品 | 欧日韩在线视频 | 男女拍拍免费视频 | 97超碰国产在线 | www.久热 | 免费婷婷 | 69精品视频在线观看 | 在线观看日韩视频 | 婷婷六月网 | 西西人体4444www高清视频 | 中文在线√天堂 | 亚洲视频在线视频 | 在线看国产一区 | 久久久精品日本 | 激情 亚洲 | 国产亚洲成人网 | 亚洲欧美日韩国产一区二区三区 | av片子在线观看 | 精品91久久久久 | 欧美激情视频一区二区三区 | 丁香花在线观看视频在线 | 久久久久久久久久久久久久av | 免费高清在线观看成人 | 最近中文字幕在线播放 | 国产精品9999| 午夜免费在线观看 | 草久久精品 | av日韩不卡| 欧美久久久一区二区三区 | 亚洲一级片免费观看 | 婷婷久久久久 | 日本高清中文字幕有码在线 | 成人黄色小说在线观看 | 毛片888 | 一区二区三区免费在线播放 | 中文字幕在线免费看线人 | 久久手机免费视频 | 日日夜夜天天人人 | 97成人精品视频在线播放 | 国产精品免费在线播放 | 日韩欧美高清一区二区 | 中文字幕国产亚洲 | 久久免费99精品久久久久久 | 美女视频免费精品 | 人人爽人人爽人人片av免 | 伊人激情综合 | 91精品蜜桃 | 永久免费精品视频 | 九热在线 | 狠狠的操你 | av大片免费在线观看 | 一区二区三区免费播放 | 国产中文字幕亚洲 | 精品国产大片 | 91久色蝌蚪 | 97福利在线 | 美女搞黄国产视频网站 | 伊人手机在线 | 成人黄性视频 | 国产精品久久久久久久久免费看 | av久久久| 国产 色| 福利网在线 | 国产精品手机在线 | 久久av影视| 国产手机在线精品 | 中文字幕视频在线播放 | 日本女人的性生活视频 | 亚洲国产日韩欧美 | 亚州av网站大全 | 香蕉影视 | 国产精品久久久精品 | 日韩区欧美久久久无人区 | 日韩成年视频 | 亚洲国产999 | 91成人精品一区在线播放69 | 国产一级片一区二区三区 | 日韩欧美一区视频 | 亚洲精品在线视频观看 | 久久99精品久久久久蜜臀 | 国产精品嫩草69影院 | 国产在线观看一 | 色插综合 | 国产精品免费在线观看视频 | 在线黄频| 国产女教师精品久久av | www..com毛片 | 日韩在线视频网 | 亚洲国产成人精品在线观看 | 亚洲精品456在线播放 | 国产精品不卡av | 久久人人97超碰精品888 | www91在线观看 | 久久国产剧场电影 | 9797在线看片亚洲精品 | 欧美在线一级片 | 日韩在线观看视频网站 | a黄色大片| 中文字幕亚洲精品在线观看 | 欧美男女爱爱视频 | 香蕉视频在线免费 | 夜色成人网 | 欧亚日韩精品一区二区在线 | 久久精品视频观看 | 国产精品一区二区三区在线 | 国产黄视频在线观看 | 亚洲精品美女在线 | 激情久久综合网 | 成人毛片一区 | 91免费视频网站在线观看 | 免费日韩高清 | 欧美日韩成人一区 | 色噜噜狠狠色综合中国 | 亚洲成人精品国产 | 一本之道乱码区 | 免费特级黄色片 | av在线播放亚洲 | 狠狠色狠狠色综合日日92 | 亚州精品一二三区 | 一级成人免费 | 国产69久久久 | 国产免费一区二区三区最新6 | 亚洲精品国精品久久99热 | 丁香久久婷婷 | 免费日韩av电影 | 99久久日韩精品视频免费在线观看 | 免费黄色在线网站 | 激情欧美一区二区三区 | 日韩欧美精选 | 97超碰福利久久精品 | 精品一区二区三区久久 | 免费合欢视频成人app | 深爱婷婷激情 | 日韩成片 | 日本韩国精品一区二区在线观看 | 激情五月婷婷激情 | 丁香婷婷色 | 精品一二 | 在线播放视频一区 | 91探花在线 | 四虎国产精品永久在线国在线 | 精品视频 | 天天躁日日躁狠狠 | 丁香六月五月婷婷 | 韩国在线一区二区 | 黄网站app在线观看免费视频 | 国产精品成人一区二区 | 福利视频| 成人在线播放av | 黄网站色成年免费观看 | 久久你懂的 | 黄色资源网站 | 亚在线播放中文视频 | 韩国在线一区二区 | 99爱精品在线 | 久久久久久久久免费 | 成人黄色毛片视频 | 91社区国产高清 | 亚洲黄色小说网址 | 波多野结衣在线播放视频 | 五月婷婷中文字幕 | 久久国产精品成人免费浪潮 | 国内精品久久久久久 | 国产99久久 | 男女拍拍免费视频 | 一区二区三区精品久久久 | 成年性视频 | 色五月情 | 亚洲一区二区天堂 | 精品在线二区 | 国产韩国精品一区二区三区 | 精品视频免费观看 | 亚洲国产精品一区二区久久hs | 天天射天天射 | 91亚洲综合 | 日韩精品无 | 亚洲 欧洲 国产 日本 综合 | 亚洲小视频在线观看 | .精品久久久麻豆国产精品 亚洲va欧美 | 九九热99视频 | 91高清在线 | 人人干人人添 | 91av在线免费看 | av一级免费 | 日本中文字幕影院 | 在线免费观看欧美日韩 | 操操操干干干 | www国产亚洲 | 日韩一区二区在线免费观看 | 日韩精品久久一区二区三区 | 日韩精品一区电影 | 日韩中文字幕视频在线观看 | 亚洲成a人片在线www | 97人人模人人爽人人喊中文字 | 欧美激情奇米色 | 天天射色综合 | 狠狠操综合网 | 亚洲a网| 免费涩涩网站 | 亚洲欧美精品在线 | 国产精品久久久久影院 | 精品一区二区三区电影 | 不卡中文字幕在线 | 四虎影视精品永久在线观看 | 永久免费毛片在线观看 | 国产日韩视频在线 | 欧美a级一区二区 | 久久综合久久久 | 国产色爽 | 国产成人精品一区二区三区福利 | 美州a亚洲一视本频v色道 | 99精品国产亚洲 | 亚洲一区美女视频在线观看免费 | 人人爽人人澡人人添人人人人 | 伊人狠狠操 | 久久久这里有精品 | 五月天激情综合网 | 国产成人精品一区二区三区 | 97精品国产97久久久久久久久久久久 | 国产黄色av| 超级碰碰免费视频 | 久久国产精品色婷婷 | 国内久久久久久 | 香蕉精品视频在线观看 | 97精品欧美91久久久久久 | 一区二区视频播放 | 国产高清av| 国产香蕉视频 | 日韩专区 在线 | 久久96 | 玖玖视频在线 | 毛片www | 夜夜躁天天躁很躁波 | 午夜精品一区二区三区免费视频 | 国产福利中文字幕 | 日韩欧美xx| 在线 成人 | 国产精品久久久毛片 | 成人黄色大片 | 色婷丁香| 91麻豆精品国产自产在线游戏 | 日韩av二区 | 天天操天天操天天操天天操 | 日韩女同av | 日韩在线观看视频一区二区三区 | 国产精品美女在线 | 国产原厂视频在线观看 | 狠狠躁天天躁综合网 | 国产精品久久久久久久久久免费 | 激情视频免费在线 | 韩国av一区 | 精品一区二区综合 | av片在线观看免费 | 在线你懂 | 精品一区二区在线免费观看 | 日韩欧美视频免费看 | 天天爽天天做 | 丁香久久久 | 色www永久免费 | 亚洲成人av片 | 久久精品牌麻豆国产大山 | 色在线观看网站 | 午夜天天操 | 在线国产能看的 | 久久久国产精品一区二区三区 | 最近2019年日本中文免费字幕 | 精品福利在线 | 色狠狠综合 | 最新av中文字幕 | 亚洲午夜久久久久久久久久久 | 日韩精品中文字幕在线不卡尤物 | 久久久受www免费人成 | 啪啪肉肉污av国网站 | 一区二区三区电影 | 日韩在线观看a | 一区二区激情视频 | 国产成人一区二区三区在线观看 | 亚洲精品国产欧美在线观看 | 婷婷六月天在线 | 国产中的精品av小宝探花 | 蜜臀一区二区三区精品免费视频 | 日韩精品aaa | 人人爱人人爽 | 久久免费黄色 | 久久久私人影院 | 午夜在线日韩 | 精品一区二区三区香蕉蜜桃 | 国产中文字幕在线观看 | 很黄很污的视频网站 | 国产中出在线观看 | 九九九热精品免费视频观看网站 | 国产精品嫩草55av | 免费福利在线 | 国产精品久久久久久欧美 | 亚洲最新视频在线播放 | 欧美精品免费视频 | 99热这里精品 | 伊人久久av | 精品久久五月天 | 久久香蕉电影 | 国产精品美女免费视频 | 久久久999 | 久久免费精品国产 | 色婷婷亚洲精品 | 99亚洲精品在线 | 久久免费播放视频 | av在线之家电影网站 | 懂色av一区二区在线播放 | a天堂免费 | 最新色站 | 日韩美女黄色片 | 亚洲视频精品 | 欧美日韩一区久久 | 久久国内免费视频 | 五月婷久久| 蜜臀av在线一区二区三区 | 色久五月 | 最新国产精品视频 | 久久久久久免费视频 | 亚洲国产中文字幕在线 | 午夜色场 | 日本最新一区二区三区 | 国产xx在线| 美女露久久 | 久久精品欧美日韩精品 | 久久短视频| 99免费看片 | www.成人sex| 亚洲国产精品va在线看黑人 | 偷拍久久久| 亚洲九九精品 | 午夜精品久久久久久久99无限制 | 午夜视频一区二区三区 | 国产区av在线 | 在线观看国产区 | av中文在线播放 | 国产在线国产 | 五月婷在线观看 | 亚洲男模gay裸体gay | 国产综合91 | 国产女v资源在线观看 | 国产福利免费看 | 国产小视频免费在线观看 | 精品久久久久久久久久久院品网 | 91在线视频播放 | 国产精品96久久久久久吹潮 | 天天操天天曰 | 色网站在线免费 | 日韩精品久久久免费观看夜色 | 成人黄色大片在线免费观看 | 久久综合成人网 | 最新国产精品久久精品 | 日韩欧美一区二区在线观看 | 国产91对白在线播 | www.久久久.com | 韩国av永久免费 | 国内精品久久久久久久影视简单 | 超碰在线观看av | 日本精品小视频 | 亚洲国产人午在线一二区 | 午夜视频在线瓜伦 | 91九色精品女同系列 | 精产嫩模国品一二三区 | 91中文字幕一区 | 色吊丝在线永久观看最新版本 | 中文字幕高清av | 福利二区视频 | 久久久久高清 | 午夜av在线免费 | 天天激情天天干 | 国产精品a久久久久 | 色综合中文综合网 | 久久久av电影 | 亚洲女人av| 欧美va电影| 国产福利资源 | 九九视频网 | 久久久精品 一区二区三区 国产99视频在线观看 | 久久国产午夜精品理论片最新版本 | 欧美一级高清片 | 欧美日韩亚洲精品在线 | 97超碰人人网| 久久深夜 | 一区二区三区四区久久 | 91亚洲精品国产 | 婷婷开心久久网 | av久久在线 | 99r精品视频在线观看 | 亚洲国产精品va在线 | 国产精品欧美一区二区三区不卡 | 美女网站视频免费都是黄 | 黄色视屏av| 久草在线精品观看 | 亚洲国产小视频在线观看 | 激情xxxx| 日韩欧美久久 | 91成品视频 | 97人人精品| 久久这里只有精品视频首页 | 香蕉视频亚洲 | 一区二区视频欧美 | 日韩精品中文字幕在线 | 久久99亚洲网美利坚合众国 | 日本99热| 国产麻豆精品在线观看 | 黄色美女免费网站 | 国产精品久久久久久久久久三级 | 国产男女无遮挡猛进猛出在线观看 | 一区二区成人国产精品 | 超碰午夜| 国产不卡一二三区 | 韩国av三级 | 欧美色精品天天在线观看视频 | 亚洲天堂自拍视频 | 国产精品一区二区三区在线免费观看 | 国产精品爽爽久久久久久蜜臀 | 一区 二区电影免费在线观看 | 中文字幕亚洲五码 | 久久午夜电影网 | 免费一级片在线观看 | 深夜成人av| 久草在线资源网 | 麻豆视频免费播放 | 欧美激情第八页 | 免费在线观看国产精品 | 一级淫片在线观看 | 狠狠五月天 | 91成人免费看片 | 国产成在线观看免费视频 | 久久9视频| 天天操天天摸天天干 | 日本久久视频 | 久要激情网 | 国产精品久久久久久一区二区 | 片黄色毛片黄色毛片 | 亚洲久草在线 | 久久av中文字幕片 | 国产精品你懂的在线观看 | 久久久久国产精品一区二区 | 久草免费在线观看视频 | 国产成人一区二区三区影院在线 | 精品久久久久免费极品大片 | 久久久久免费观看 | 国产精彩视频一区 | 天堂网av 在线 | 国产精品6999成人免费视频 | 久久蜜臀一区二区三区av | 96av视频 | 免费黄色网址大全 | 91香蕉视频黄色 | 五月天激情综合 | 在线观看网站你懂的 | 午夜视频一区二区三区 | 日本h视频在线观看 | av三区在线| 久久久精品小视频 | 亚洲精品国产精品国自产 | 国产麻豆精品在线观看 | 精品国产一二区 | 免费在线观看黄色网 | 日本在线观看中文字幕 | 在线观看91视频 | 成人免费xxxxxx视频 | 日韩一区二区三区高清免费看看 | 黄色软件视频大全免费下载 | 成人国产精品久久久 | 欧美日本不卡视频 | 欧美精品v国产精品v日韩精品 | 四虎成人av | 亚洲精品久久久久58 | 四虎天堂 | 久久国产精品99久久久久久丝袜 | 日韩免费观看av | 精品国产自 | 国产精品自拍在线 | 黄色一级大片在线免费看国产一 | 久久成人亚洲欧美电影 | 久久综合欧美精品亚洲一区 | 婷婷丁香社区 | 91视频成人免费 | 操老逼免费视频 | 伊人网av | 狠狠狠狠狠干 | 天天天天色射综合 | 波多野结衣视频网址 | 最近中文字幕mv免费高清在线 | 91超碰免费在线 | 中文字幕在线观看播放 | 日韩国产在线观看 | 欧美不卡视频在线 | 欧美日韩国产二区三区 | 亚洲精品乱码久久久久v最新版 | 久草.com| 国产在线观看91 | 六月丁香激情综合 | 久久tv | 日韩精品久久久久久 | 又爽又黄又刺激的视频 | 人人玩人人爽 | 欧美男女爱爱视频 | 亚洲精品综合在线观看 | 在线视频日韩一区 | a级国产乱理论片在线观看 伊人宗合网 | 亚洲精品视频第一页 | 美州a亚洲一视本频v色道 | 欧美另类性 | 亚洲激情校园春色 | 永久免费视频国产 | 国产精品久久伊人 | 色视频在线免费 | 亚洲三级在线播放 | 久久影院午夜论 | 一级黄色片在线观看 | 天天干天天操天天射 | 久久综合狠狠狠色97 | 国产破处精品 | 欧美一级片免费在线观看 | 激情片av| 精品视频久久 | 综合激情| 最近日本韩国中文字幕 | 夜夜骑日日 | 久久艹在线 | 亚洲精品字幕在线观看 | 九九久久久久久久久激情 | 国产爽妇网 | 日韩在线看片 | 91人人爽久久涩噜噜噜 | 成年人黄色在线观看 |