日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区

您的位置:首頁技術文章
文章詳情頁

SpringBoot和Redis實現Token權限認證的實例講解

瀏覽:19日期:2023-03-25 08:09:52
一、引言

登陸權限控制是每個系統都應必備的功能,實現方法也有好多種。下面使用Token認證來實現系統的權限訪問。

功能描述:

用戶登錄成功后,后臺返回一個token給調用者,同時自定義一個@AuthToken注解,被該注解標注的API請求都需要進行token效驗,效驗通過才可以正常訪問,實現接口級的鑒權控制。

同時token具有生命周期,在用戶持續一段時間不進行操作的話,token則會過期,用戶一直操作的話,則不會過期。

二、環境

SpringBoot

Redis(Docke中鏡像)

MySQL(Docker中鏡像)

三、流程分析1、流程分析

(1)、客戶端登錄,輸入用戶名和密碼,后臺進行驗證,如果驗證失敗則返回登錄失敗的提示。

如果驗證成功,則生成 token 然后將 username 和 token 雙向綁定 (可以根據 username 取出 token 也可以根據 token 取出username)存入redis,同時使用 token+username 作為key把當前時間戳也存入redis。并且給它們都設置過期時間。

(2)、每次請求接口都會走攔截器,如果該接口標注了@AuthToken注解,則要檢查客戶端傳過來的Authorization字段,獲取 token。

由于 token 與 username 雙向綁定,可以通過獲取的 token 來嘗試從 redis 中獲取 username,如果可以獲取則說明 token 正確,反之,說明錯誤,返回鑒權失敗。

(3)、token可以根據用戶使用的情況來動態的調整自己過期時間。

在生成 token 的同時也往 redis 里面存入了創建 token 時的時間戳,每次請求被攔截器攔截 token 驗證成功之后,將當前時間與存在 redis 里面的 token 生成時刻的時間戳進行比較,當當前時間的距離創建時間快要到達設置的redis過期時間的話,就重新設置token過期時間,將過期時間延長。

如果用戶在設置的 redis 過期時間的時間長度內沒有進行任何操作(沒有發請求),則token會在redis中過期。

四、具體代碼實現1、自定義注解

@Target({ElementType.METHOD, ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)public @interface AuthToken {}2、登陸控制器

@RestControllerpublic class welcome { Logger logger = LoggerFactory.getLogger(welcome.class); @Autowired Md5TokenGenerator tokenGenerator; @Autowired UserMapper userMapper; @GetMapping('/welcome') public String welcome(){ return 'welcome token authentication'; } @RequestMapping(value = '/login', method = RequestMethod.GET) public ResponseTemplate login(String username, String password) { logger.info('username:'+username+' password:'+password); User user = userMapper.getUser(username,password); logger.info('user:'+user); JSONObject result = new JSONObject(); if (user != null) { Jedis jedis = new Jedis('192.168.1.106', 6379); String token = tokenGenerator.generate(username, password); jedis.set(username, token); //設置key生存時間,當key過期時,它會被自動刪除,時間是秒 jedis.expire(username, ConstantKit.TOKEN_EXPIRE_TIME); jedis.set(token, username); jedis.expire(token, ConstantKit.TOKEN_EXPIRE_TIME); Long currentTime = System.currentTimeMillis(); jedis.set(token + username, currentTime.toString()); //用完關閉 jedis.close(); result.put('status', '登錄成功'); result.put('token', token); } else { result.put('status', '登錄失敗'); } return ResponseTemplate.builder() .code(200) .message('登錄成功') .data(result) .build(); } //測試權限訪問 @RequestMapping(value = 'test', method = RequestMethod.GET) @AuthToken public ResponseTemplate test() { logger.info('已進入test路徑'); return ResponseTemplate.builder() .code(200) .message('Success') .data('test url') .build(); }}3、攔截器

@Slf4jpublic class AuthorizationInterceptor implements HandlerInterceptor { //存放鑒權信息的Header名稱,默認是Authorization private String httpHeaderName = 'Authorization'; //鑒權失敗后返回的錯誤信息,默認為401 unauthorized private String unauthorizedErrorMessage = '401 unauthorized'; //鑒權失敗后返回的HTTP錯誤碼,默認為401 private int unauthorizedErrorCode = HttpServletResponse.SC_UNAUTHORIZED; //存放登錄用戶模型Key的Request Key public static final String REQUEST_CURRENT_KEY = 'REQUEST_CURRENT_KEY'; @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { if (!(handler instanceof HandlerMethod)) { return true; } HandlerMethod handlerMethod = (HandlerMethod) handler; Method method = handlerMethod.getMethod(); // 如果打上了AuthToken注解則需要驗證token if (method.getAnnotation(AuthToken.class) != null || handlerMethod.getBeanType().getAnnotation(AuthToken.class) != null) { String token = request.getParameter(httpHeaderName); log.info('Get token from request is {} ', token); String username = ''; Jedis jedis = new Jedis('192.168.1.106', 6379); if (token != null && token.length() != 0) { username = jedis.get(token); log.info('Get username from Redis is {}', username); } if (username != null && !username.trim().equals('')) { Long tokeBirthTime = Long.valueOf(jedis.get(token + username)); log.info('token Birth time is: {}', tokeBirthTime); Long diff = System.currentTimeMillis() - tokeBirthTime; log.info('token is exist : {} ms', diff); if (diff > ConstantKit.TOKEN_RESET_TIME) { jedis.expire(username, ConstantKit.TOKEN_EXPIRE_TIME); jedis.expire(token, ConstantKit.TOKEN_EXPIRE_TIME); log.info('Reset expire time success!'); Long newBirthTime = System.currentTimeMillis(); jedis.set(token + username, newBirthTime.toString()); } //用完關閉 jedis.close(); request.setAttribute(REQUEST_CURRENT_KEY, username); return true; } else { JSONObject jsonObject = new JSONObject(); PrintWriter out = null; try { response.setStatus(unauthorizedErrorCode); response.setContentType(MediaType.APPLICATION_JSON_VALUE); jsonObject.put('code', ((HttpServletResponse) response).getStatus()); jsonObject.put('message', HttpStatus.UNAUTHORIZED); out = response.getWriter(); out.println(jsonObject); return false; } catch (Exception e) { e.printStackTrace(); } finally { if (null != out) { out.flush(); out.close(); } } } } request.setAttribute(REQUEST_CURRENT_KEY, null); return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { }}4、測試結果

SpringBoot和Redis實現Token權限認證的實例講解

SpringBoot和Redis實現Token權限認證的實例講解

五、小結

登陸權限控制,實際上利用的就是攔截器的攔截功能。因為每一次請求都要通過攔截器,只有攔截器驗證通過了,才能訪問想要的請求路徑,所以在攔截器中做校驗Token校驗。

想要代碼,可以去GitHub上查看。

https://github.com/Hofanking/token-authentication.git

攔截器介紹,可以參考 這篇文章

補充:springboot+spring security+redis實現登錄權限管理

筆者負責的電商項目的技術體系是基于SpringBoot,為了實現一套后端能夠承載ToB和ToC的業務,需要完善現有的權限管理體系。

在查看Shiro和Spring Security對比后,筆者認為Spring Security更加適合本項目使用,可以總結為以下2點:

1、基于攔截器的權限校驗邏輯,可以針對ToB的業務接口來做相關的權限校驗,以筆者的項目為例,ToB的接口請求路徑以/openshop/api/開頭,可以根據接口請求路徑配置全局的ToB的攔截器;

2、Spring Security的權限管理模型更簡單直觀,對權限、角色和用戶做了很好的解耦。

以下介紹本項目的實現步驟

一、在項目中添加Spring相關依賴

<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> <version>1.5.3.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>4.3.8.RELEASE</version> </dependency>二、使用模板模式定義權限管理攔截器抽象類

public abstract class AbstractAuthenticationInterceptor extends HandlerInterceptorAdapter implements InitializingBean { @Resource private AccessDecisionManager accessDecisionManager; @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { //檢查是否登錄 String userId = null; try { userId = getUserId(); }catch (Exception e){ JsonUtil.renderJson(response,403,'{}'); return false; } if(StringUtils.isEmpty(userId)){ JsonUtil.renderJson(response,403,'{}'); return false; } //檢查權限 Collection<? extends GrantedAuthority> authorities = getAttributes(userId); Collection<ConfigAttribute> configAttributes = getAttributes(request); return accessDecisionManager.decide(authorities,configAttributes); } //獲取用戶id public abstract String getUserId(); //根據用戶id獲取用戶的角色集合 public abstract Collection<? extends GrantedAuthority> getAttributes(String userId); //查詢請求需要的權限 public abstract Collection<ConfigAttribute> getAttributes(HttpServletRequest request);}三、權限管理攔截器實現類 AuthenticationInterceptor

@Componentpublic class AuthenticationInterceptor extends AbstractAuthenticationInterceptor { @Resource private SessionManager sessionManager; @Resource private UserPermissionService customUserService; @Override public String getUserId() { return sessionManager.obtainUserId(); } @Override public Collection<? extends GrantedAuthority> getAttributes(String s) { return customUserService.getAuthoritiesById(s); } @Override public Collection<ConfigAttribute> getAttributes(HttpServletRequest request) { return customUserService.getAttributes(request); } @Override public void afterPropertiesSet() throws Exception { }}四、用戶Session信息管理類

集成redis維護用戶session信息

@Componentpublic class SessionManager { private static final Logger logger = LoggerFactory.getLogger(SessionManager.class); @Autowired private RedisUtils redisUtils; public SessionManager() { } public UserInfoDTO obtainUserInfo() { UserInfoDTO userInfoDTO = null; try { String token = this.obtainToken(); logger.info('=======token=========', token); if (StringUtils.isEmpty(token)) { LemonException.throwLemonException(AccessAuthCode.sessionExpired.getCode(), AccessAuthCode.sessionExpired.getDesc()); } userInfoDTO = (UserInfoDTO)this.redisUtils.obtain(this.obtainToken(), UserInfoDTO.class); } catch (Exception var3) { logger.error('obtainUserInfo ex:', var3); } if (null == userInfoDTO) { LemonException.throwLemonException(AccessAuthCode.sessionExpired.getCode(), AccessAuthCode.sessionExpired.getDesc()); } return userInfoDTO; } public String obtainUserId() { return this.obtainUserInfo().getUserId(); } public String obtainToken() { HttpServletRequest request = ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest(); String token = request.getHeader('token'); return token; } public UserInfoDTO createSession(UserInfoDTO userInfoDTO, long expired) { String token = UUIDUtil.obtainUUID('token.'); userInfoDTO.setToken(token); if (expired == 0L) { this.redisUtils.put(token, userInfoDTO); } else { this.redisUtils.put(token, userInfoDTO, expired); } return userInfoDTO; } public void destroySession() { String token = this.obtainToken(); if (StringUtils.isNotBlank(token)) { this.redisUtils.remove(token); } }}五、用戶權限管理service

@Servicepublic class UserPermissionService { @Resource private SysUserDao userDao; @Resource private SysPermissionDao permissionDao; private HashMap<String, Collection<ConfigAttribute>> map =null; /** * 加載資源,初始化資源變量 */ public void loadResourceDefine(){ map = new HashMap<>(); Collection<ConfigAttribute> array; ConfigAttribute cfg; List<SysPermission> permissions = permissionDao.findAll(); for(SysPermission permission : permissions) { array = new ArrayList<>(); cfg = new SecurityConfig(permission.getName()); array.add(cfg); map.put(permission.getUrl(), array); } }/** * @Author zhangs * @Description 獲取用戶權限列表 * @Date 18:56 2019/11/11 **/ public List<GrantedAuthority> getAuthoritiesById(String userId) { SysUserRspDTO user = userDao.findById(userId); if (user != null) { List<SysPermission> permissions = permissionDao.findByAdminUserId(user.getUserId()); List<GrantedAuthority> grantedAuthorities = new ArrayList <>(); for (SysPermission permission : permissions) { if (permission != null && permission.getName()!=null) { GrantedAuthority grantedAuthority = new SimpleGrantedAuthority(permission.getName()); grantedAuthorities.add(grantedAuthority); } } return grantedAuthorities; } return null; } /* * * @Author zhangs * @Description 獲取當前請求所需權限 * @Date 18:57 2019/11/11 **/ public Collection<ConfigAttribute> getAttributes(HttpServletRequest request) throws IllegalArgumentException { if(map !=null) map.clear(); loadResourceDefine(); AntPathRequestMatcher matcher; String resUrl; for(Iterator<String> iter = map.keySet().iterator(); iter.hasNext(); ) { resUrl = iter.next(); matcher = new AntPathRequestMatcher(resUrl); if(matcher.matches(request)) { return map.get(resUrl); } } return null; }}六、權限校驗類 AccessDecisionManager

通過查看authorities中的權限列表是否含有configAttributes中所需的權限,判斷用戶是否具有請求當前資源或者執行當前操作的權限。

@Servicepublic class AccessDecisionManager { public boolean decide(Collection<? extends GrantedAuthority> authorities, Collection<ConfigAttribute> configAttributes) throws AccessDeniedException, InsufficientAuthenticationException { if(null== configAttributes || configAttributes.size() <=0) { return true; } ConfigAttribute c; String needRole; for(Iterator<ConfigAttribute> iter = configAttributes.iterator(); iter.hasNext(); ) { c = iter.next(); needRole = c.getAttribute(); for(GrantedAuthority ga : authorities) { if(needRole.trim().equals(ga.getAuthority())) { return true; } } } return false; }}七、配置攔截規則

@Configurationpublic class WebAppConfigurer extends WebMvcConfigurerAdapter { @Resource private AbstractAuthenticationInterceptor authenticationInterceptor; @Override public void addInterceptors(InterceptorRegistry registry) { // 多個攔截器組成一個攔截器鏈 // addPathPatterns 用于添加攔截規則 // excludePathPatterns 用戶排除攔截 //對來自/openshop/api/** 這個鏈接來的請求進行攔截 registry.addInterceptor(authenticationInterceptor).addPathPatterns('/openshop/api/**'); super.addInterceptors(registry); }}八 相關表說明

用戶表 sys_user

CREATE TABLE `sys_user` ( `user_id` varchar(64) NOT NULL COMMENT ’用戶ID’, `username` varchar(255) DEFAULT NULL COMMENT ’登錄賬號’, `first_login` datetime(6) NOT NULL COMMENT ’首次登錄時間’, `last_login` datetime(6) NOT NULL COMMENT ’上次登錄時間’, `pay_pwd` varchar(100) DEFAULT NULL COMMENT ’支付密碼’, `chant_id` varchar(64) NOT NULL DEFAULT ’-1’ COMMENT ’關聯商戶id’, `create_time` datetime DEFAULT NULL COMMENT ’創建時間’, `modify_time` datetime DEFAULT NULL COMMENT ’修改時間’, PRIMARY KEY (`user_id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4

角色表 sys_role

CREATE TABLE `sys_role` ( `role_id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(255) DEFAULT NULL, `create_time` datetime DEFAULT NULL COMMENT ’創建時間’, `modify_time` datetime DEFAULT NULL COMMENT ’修改時間’, PRIMARY KEY (`role_id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4

用戶角色關聯表 sys_role_user

CREATE TABLE `sys_role_user` ( `id` int(11) NOT NULL AUTO_INCREMENT, `sys_user_id` varchar(64) DEFAULT NULL, `sys_role_id` int(11) DEFAULT NULL, PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4

權限表 sys_premission

CREATE TABLE `sys_permission` ( `permission_id` int(11) NOT NULL, `name` varchar(255) DEFAULT NULL COMMENT ’權限名稱’, `description` varchar(255) DEFAULT NULL COMMENT ’權限描述’, `url` varchar(255) DEFAULT NULL COMMENT ’資源url’, `check_pwd` int(2) NOT NULL DEFAULT ’1’ COMMENT ’是否檢查支付密碼:0不需要 1 需要’, `check_sms` int(2) NOT NULL DEFAULT ’1’ COMMENT ’是否校驗短信驗證碼:0不需要 1 需要’, `create_time` datetime DEFAULT NULL COMMENT ’創建時間’, `modify_time` datetime DEFAULT NULL COMMENT ’修改時間’, PRIMARY KEY (`permission_id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4

角色權限關聯表 sys_permission_role

CREATE TABLE `sys_permission_role` ( `id` int(11) NOT NULL AUTO_INCREMENT, `role_id` int(11) DEFAULT NULL, `permission_id` int(11) DEFAULT NULL, PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4

以上為個人經驗,希望能給大家一個參考,也希望大家多多支持好吧啦網。如有錯誤或未考慮完全的地方,望不吝賜教。

標簽: Spring
相關文章:
日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区
久久久久久久久久久妇女 | 午夜av成人| 国产日韩亚洲| 国产欧美一区二区三区精品观看 | 在线一区视频| 日本 国产 欧美色综合| 91精品一区国产高清在线gif | 日韩av网站在线免费观看| 亚洲精品中文字幕99999| 韩国一区二区三区视频| 亚洲精品看片| 999国产精品999久久久久久| 亚洲精品成人一区| 亚洲精品一级| 在线国产一区二区| 性欧美精品高清| 日韩成人亚洲| 日韩激情综合| 99在线精品免费视频九九视| 日韩专区欧美专区| 精品国产91| 精品中文在线| 四虎影视精品| 亚洲大全视频| 日韩国产欧美一区二区| 精品资源在线| 国产日韩欧美一区二区三区 | 亚洲国产专区校园欧美| 国产欧美亚洲一区| 蜜桃久久久久久久| 正在播放日韩精品| 日本а中文在线天堂| 亚洲精品精选| 日韩在线黄色| 欧美成a人片免费观看久久五月天| 麻豆国产精品| 日韩大片在线播放| 亚欧洲精品视频在线观看| 久久久精品五月天| 精品久久福利| 99精品在线| 新版的欧美在线视频| 成人片免费看| 性色一区二区| 国产黄色精品| 成人在线免费观看91| 国产精品黑丝在线播放| 国产欧美日韩免费观看| 丝袜美腿成人在线| 欧美一区不卡| 麻豆一区二区三区| 群体交乱之放荡娇妻一区二区| 免费精品国产的网站免费观看| 日韩精选在线| 国产超碰精品| a日韩av网址| 伊人国产精品| 亚洲精品乱码久久久久久蜜桃麻豆 | 日日摸夜夜添夜夜添国产精品| 在线精品亚洲| 久久久久.com| 国产精品普通话对白| 精品国产网站| 久久久久.com| 精品视频久久| 偷拍欧美精品| 久久精品xxxxx| 天堂网av成人| 高清一区二区三区av| 日韩av在线免费观看不卡| 精品丝袜久久| 激情久久99| 国户精品久久久久久久久久久不卡| 成人午夜毛片| 亚洲精品极品少妇16p| 久久99视频| 蜜桃视频免费观看一区| 欧美精品一线| 另类综合日韩欧美亚洲| 久久只有精品| 午夜一级在线看亚洲| 精品国产一区二区三区噜噜噜| 免费久久精品| 国产精品成人一区二区不卡| 秋霞国产精品| 欧美1区2区3区| 国产欧美在线| 另类av一区二区| 在线亚洲国产精品网站| 欧美一区久久久| 欧美日韩国产精品一区二区亚洲| 久久天堂影院| 日韩精品福利一区二区三区| 成人午夜亚洲| 中文字幕亚洲精品乱码| 亚洲91在线| 亚洲精品一二三区区别| 97精品国产福利一区二区三区| 最新亚洲一区| 久久国内精品| 激情91久久| 亚洲黄页一区| 另类亚洲自拍| 国产午夜久久| 热久久久久久| 国产欧美一区二区三区国产幕精品 | 欧美日本精品| 日本蜜桃在线观看视频| 欧美精品国产白浆久久久久| 欧美aa国产视频| 日韩国产在线| 亚洲欧洲美洲av| 91亚洲人成网污www| 极品av在线| 国产精久久久| 亚洲69av| 麻豆精品蜜桃视频网站| 欧美亚洲国产激情| 国产一区二区三区天码| 日韩国产在线观看| av亚洲在线观看| 日韩免费视频| 午夜精品久久久久久久久久蜜桃| 久久久久九九精品影院| 欧美特黄一级大片| 亚洲手机在线| 91精品国产91久久久久久黑人| 91精品韩国| 日韩在线观看一区二区| 精品中文在线| 麻豆极品一区二区三区| 激情久久久久久| 久久麻豆视频| 久久人人精品| 日韩一区免费| 五月天激情综合网| 在线亚洲人成| 日韩和欧美的一区| 亚洲成a人片| 日韩一区精品视频| 天堂日韩电影| 国产精品一区二区三区av| 久久av日韩| 欧美一级网址| 国产日韩三级| 九九综合在线| 亚洲一区二区小说| 国产一区二区三区日韩精品| 国产精品流白浆在线观看| 成人日韩av| 另类av一区二区| 国产精品久久久久久久久久齐齐 | 日本欧美一区二区| 亚洲综合日韩| 91精品婷婷色在线观看| 国产视频久久| 精品福利久久久| 视频一区二区国产| 亚洲一区观看| 99re国产精品| 国产成人精品免费视| 老鸭窝毛片一区二区三区| 一区二区国产精品| 午夜久久中文| 伊人影院久久| 伊人久久视频| 日韩免费视频| 国产精品66| 国产美女久久| 天堂va欧美ⅴa亚洲va一国产| av中文字幕在线观看第一页| 欧美一级全黄| 国产精品v日韩精品v欧美精品网站| 欧美jjzz| 国产欧美一区二区三区国产幕精品 | 日韩一二三区在线观看| 99re国产精品| 欧美一级二区| 视频一区视频二区中文字幕| 99久久激情| 中文精品电影| 日韩激情综合| 欧美日韩国产一区二区三区不卡| 99久久亚洲精品| 激情欧美丁香| 日韩精品一区第一页| 日韩精品一级中文字幕精品视频免费观看 | 久久国产影院| 天使萌一区二区三区免费观看| 丝瓜av网站精品一区二区| 亚洲一级特黄| 国产视频欧美| 亚洲精品麻豆| 久草精品视频| 日韩欧美一区二区三区在线视频 | 成人羞羞视频播放网站| 国产中文在线播放| 日本免费一区二区三区四区| 国产精品调教| 国产日韩精品视频一区二区三区|