<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          實戰(zhàn):十分鐘實現(xiàn)基于JWT前后端分離的權(quán)限框架

          共 6920字,需瀏覽 14分鐘

           ·

          2020-08-26 15:39

          前言

          面試過很多Java開發(fā),能把權(quán)限這塊說的清楚的實在是不多,很多人因為公司項目職責(zé)問題,很難學(xué)到這類相關(guān)的流程和技術(shù),本文梳理一個簡單的場景,實現(xiàn)一個基于jwt前后端分離的權(quán)限框架。

          簡易流程

          登錄獲取票據(jù)和緩存信息

          image-20200709160301317

          鑒權(quán)流程

          image-20200709160427929

          技術(shù)棧和功能規(guī)劃

          本文技術(shù)選型為SpringBoot+JWT+Redis, 實現(xiàn)上圖的登錄流程和鑒權(quán)流程,并提供完整項目代碼。

          「本項目已實現(xiàn)如下功能」

          • 跨域配置
          • jwt集成
          • redis集成
          • BaseController封裝,方便取出用戶信息
          • 攔截器和白名單
          • 全局異常
          • jwt工具類封裝
          • redis工具類封裝
          • redis枚舉Key封裝

          Redis安裝和啟動

          使用Docker一行命令構(gòu)建啟動Redis,命令如下

          ?docker?run?-itd?--name?redis-test?-p?6379:6379?redis?--requirepass?"123456redis"

          指定端口:6379

          指定密碼:123456redis

          客戶端連接測試,問題不大~

          創(chuàng)建SpringBoot項目并引入JWT依賴


          ??io.jsonwebtoken
          ??jjwt
          ??0.9.1

          其實主要是引了這個包,其他的就不貼出來了。主要有redis以及json相關(guān)的,完整代碼都在項目可以自己看

          寫一個登陸方法

          UserController

          ??@PostMapping("/login")
          ????public?UserVO?login(@RequestBody?LoginDTO?loginDTO)??{
          ????????return?userService.login(loginDTO);
          ????}

          UserService

          用戶信息就模擬的了,都看的懂。登錄成功后根據(jù)uid生產(chǎn)jwt,然后緩存到redis,封裝結(jié)果給到前端

          package?com.lzp.auth.service;

          @Service
          public?class?UserService?{

          ????@Value("${server.session.timeout:3000}")
          ????private?Long?timeout;

          ????@Autowired
          ????private?RedisUtils?redisUtils;

          ????final?static?String?USER_NAME?=?"admin";

          ????//密碼?演示用就不做加密處理了
          ????final?static?String?PWD?=?"admin";


          ????public?UserVO?login(LoginDTO?loginDTO){

          ????????User?user?=?getByName(loginDTO.getUserName());

          ????????//用戶信息校驗和查詢
          ????????if?(user?==?null){
          ????????????throw?new?ServiceException(ResultCodeEnum.LOGIN_FAIL);
          ????????}
          ????????//密碼校驗
          ????????if(!PWD.equals(loginDTO.getPwd())){
          ????????????throw?new?ServiceException(ResultCodeEnum.LOGIN_FAIL);
          ????????}

          ????????//緩存用戶信息并設(shè)置過期時間
          ????????UserVO?userVO?=?new?UserVO();
          ????????userVO.setName(user.getName());
          ????????userVO.setUid(user.getUid());
          ????????userVO.setToken(JWTUtils.generate(user.getUid()));

          ????????//信息入庫redis
          ????????redisUtils.set(RedisKeyEnum.OAUTH_APP_TOKEN.keyBuilder(userVO.getUid()),?JSONObject.toJSONString(userVO),?timeout);

          ????????return?userVO;
          ????}
          ????/**
          ?????*?通過用戶名獲取用戶
          ?????*?@param?name
          ?????*?@return
          ?????*/

          ????public?User?getByName(String?name){
          ????????User?user?=?null;
          ????????if(USER_NAME.equals(name)){
          ????????????user?=??new?User("1","張三","Aa123456");
          ????????}
          ????????return?user;
          ????}

          }

          定義登錄攔截器

          LoginInterceptor

          package?com.lzp.auth.config;


          import?com.lzp.auth.exception.ServiceException;
          import?com.lzp.auth.utils.JWTUtils;
          import?com.lzp.auth.utils.ResultCodeEnum;
          import?com.lzp.auth.utils.SessionContext;
          import?io.jsonwebtoken.Claims;
          import?lombok.extern.slf4j.Slf4j;
          import?org.springframework.beans.factory.annotation.Autowired;
          import?org.springframework.data.redis.core.StringRedisTemplate;
          import?org.springframework.util.StringUtils;
          import?org.springframework.web.servlet.ModelAndView;
          import?org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

          import?javax.servlet.http.HttpServletRequest;
          import?javax.servlet.http.HttpServletResponse;

          @Slf4j
          public?class?LoginInterceptor?extends?HandlerInterceptorAdapter?{


          ????@Autowired
          ????StringRedisTemplate?redisTemplate;


          ????@Override
          ????public?boolean?preHandle(HttpServletRequest?request,?HttpServletResponse?response,?Object?handler)?throws?Exception?{
          ????????String?token?=?request.getHeader("token");
          ????????String?requestURI?=?request.getRequestURI().replaceAll("/+",?"/");

          ????????log.info("requestURI:{}",requestURI);

          ????????if?(StringUtils.isEmpty(token))?{
          ????????????throw?new?ServiceException(ResultCodeEnum.AUTH_FAIL);
          ????????}

          ????????Claims?claim?=?JWTUtils.getClaim(token);
          ????????if(claim?==?null){
          ????????????throw?new?ServiceException(ResultCodeEnum.AUTH_FAIL);
          ????????}

          ????????String?uid?=?null;
          ????????try?{
          ????????????uid?=?JWTUtils.getOpenId(token);
          ????????}?catch?(Exception?e)?{
          ????????????throw?new?ServiceException(ResultCodeEnum.AUTH_FAIL);
          ????????}

          ????????//用戶id放到上下文?可以當(dāng)前請求進(jìn)行傳遞
          ????????request.setAttribute(SessionContext.USER_ID_KEY,?uid);
          ????????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?{
          ????}


          }

          配置跨域、資源、定義攔截器、加白名單

          package?com.lzp.auth.config;

          import?org.springframework.beans.BeansException;
          import?org.springframework.context.ApplicationContext;
          import?org.springframework.context.ApplicationContextAware;
          import?org.springframework.context.annotation.Bean;
          import?org.springframework.context.annotation.Configuration;
          import?org.springframework.web.cors.CorsConfiguration;
          import?org.springframework.web.cors.reactive.CorsWebFilter;
          import?org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource;
          import?org.springframework.web.servlet.config.annotation.InterceptorRegistry;
          import?org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
          import?org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
          import?org.springframework.web.util.pattern.PathPatternParser;

          @Configuration
          public?class?WebMvcConfig?extends?WebMvcConfigurerAdapter?implements?ApplicationContextAware?{


          ????private?ApplicationContext?applicationContext;

          ????public?WebMvcConfig()?{
          ????????super();
          ????}

          ????@Override
          ????public?void?addResourceHandlers(ResourceHandlerRegistry?registry)?{
          ????????super.addResourceHandlers(registry);
          ????}

          ????@Override
          ????public?void?setApplicationContext(ApplicationContext?applicationContext)?throws?BeansException?{
          ????????this.applicationContext?=?applicationContext;
          ????}

          ????@Bean
          ????public?CorsWebFilter?corsFilter()?{
          ????????CorsConfiguration?config?=?new?CorsConfiguration();
          ????????config.addAllowedMethod("*");
          ????????config.addAllowedOrigin("*");
          ????????config.addAllowedHeader("*");
          ????????UrlBasedCorsConfigurationSource?source?=?new?UrlBasedCorsConfigurationSource(new?PathPatternParser());
          ????????source.registerCorsConfiguration("/**",?config);
          ????????return?new?CorsWebFilter(source);
          ????}


          ????@Bean
          ????LoginInterceptor?loginInterceptor()?{
          ????????return?new?LoginInterceptor();
          ????}


          ????@Override
          ????public?void?addInterceptors(InterceptorRegistry?registry)?{

          ????????//攔截規(guī)則:除了login,其他都攔截判斷
          ????????registry.addInterceptor(loginInterceptor())
          ????????????????.addPathPatterns("/**")
          ????????????????.excludePathPatterns("/user/login");

          ????????super.addInterceptors(registry);
          ????}

          }

          「postMan調(diào)試」

          模擬成功和失敗場景

          成功如上圖,返回用戶信息和Token

          失敗如上圖

          測試非白名單接口


          「使用token再來訪問當(dāng)前接口」

          完美~

          至此本項目就完美結(jié)束了哦

          項目代碼

          https://github.com/pengziliu/GitHub-code-practice

          這個倉庫除了這個還有更多精彩代碼喲


          已擼完部分開源輪子,更多精彩正在路上

          模塊所屬開源項目項目介紹
          springboot_api_encryptionrsa-encrypt-body-spring-bootSpring Boot接口加密,可以對返回值、參數(shù)值通過注解的方式自動加解密 。
          simpleimage-demosimpleimage圖片處理工具類,具有加水印、壓縮、裁切等功能
          xxl-job-demoxxl-job分布式定時任務(wù)使用場景
          xxl-sso-demoxxl-sso單點登錄功能
          vuepress-demovuepress建立自己的知識檔案庫
          xxl-conf-demoxxl-conf分布式配置中心
          Shardingsphere-demoShardingsphere分庫分表
          easyexcel-demoeasyexcelexcel操作工具類

          kaptcha-demokaptcha前后端分離驗證碼方案

          —?【 THE END 】—
          本公眾號全部博文已整理成一個目錄,請在公眾號里回復(fù)「m」獲取!


          3T技術(shù)資源大放送!包括但不限于:Java、C/C++,Linux,Python,大數(shù)據(jù),人工智能等等。在公眾號內(nèi)回復(fù)「1024」,即可免費獲取!!




          瀏覽 71
          點贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  久久E6热在线观看 | 91成人三级片 | 天天摸天天添 | 91精品日产一二三区乱码 | 欧美逼网站 |