1-(2)、服務(wù)鑒權(quán)JWT使用

1、 JWT工具類編寫

(1)common工程引入依賴(考慮到工具類的通用性)
   <!--jjwt-->
   <dependency>
       <groupId>io.jsonwebtoken</groupId>
       <artifactId>jjwt</artifactId>
       <version>0.9.0</version>
   </dependency>
(2)修改common工程,創(chuàng)建util.JwtUtil
package util;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.boot.context.properties.ConfigurationProperties;
import java.util.Date;

@ConfigurationProperties("jwt.config")
public class JwtUtil {

    private String key; //關(guān)鍵字(鹽)
    
    private long ttl;  //一個(gè)小時(shí)(過期時(shí)間)

    public String getKey() {
        return key;
    }

    public void setKey(String key) {
        this.key = key;
    }

    public long getTtl() {
        return ttl;
    }

    public void setTtl(long ttl) {
        this.ttl = ttl;
    }

    /**
     * 生成JWT
     *
     * @param id
     * @param subject
     * @return
     */
    public String createJWT(String id, String subject, String roles) {
        long nowMillis = System.currentTimeMillis();
        Date now = new Date(nowMillis);
        JwtBuilder builder = Jwts.builder()
            .setId(id)           //用戶id
            .setSubject(subject) //用戶名
            .setIssuedAt(now)   //用于設(shè)置簽發(fā)時(shí)間
            .signWith(SignatureAlgorithm.HS256, key) //用于設(shè)置簽名秘鑰
            .claim("roles", roles);  //自定義,設(shè)置用戶角色
            if (ttl > 0) {
                builder.setExpiration( new Date( nowMillis + ttl));  //設(shè)置過期時(shí)間
            }
        return builder.compact(); //轉(zhuǎn)化成字符串返回
    }

    /**
     * 解析JWT
     * @param jwtStr
     * @return
     */
    public Claims parseJWT(String jwtStr){
        return  Jwts.parser()
                .setSigningKey(key)
                .parseClaimsJws(jwtStr)
                .getBody();
    }
}
(3)修改user工程的application.yml, 添加配置
#jwt相關(guān)
jwt:
  config:
    key: justIT
    ttl: 3600000

2、管理員登陸后臺(tái)簽發(fā)token

(1)配置bean,修改user工程Application類
    @Bean
    public JwtUtil jwtUtil(){
        return new JwtUtil();
    }
(2)修改AdminController的login方法
    @Autowired
    private JwtUtil jwtUtil;
    
    /**
     * @Description: //TODO 用戶登錄
     * @Param: []
     * @return: entity.Result
     */
    @PostMapping("/login")
    public Result login(@RequestBody Admin admin){
        admin = adminService.login(admin);
        if (admin == null){
            return new Result(false, StatusCode.LOGINERROR, "登錄失敗");
        }
        //使得前后端通話
        //生成令牌
        Map<String, String> map = new HashMap<>();
        String token = jwtUtil.createJWT(admin.getId(), admin.getLoginname(), "admin");
        map.put("roles", "admin");
        map.put("token", token);
        return new Result(true, StatusCode.OK, "登錄成功", map);
    }
    

測(cè)試運(yùn)行結(jié)果:

{
  "flag": true,   
  "code": 20000,   
  "message": "登陸成功",   
  "data": {     
            "token":  "eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiI5ODQzMjc1MDc4ODI5MzgzNjgiLCJzdWIiOiJ4aWFvbWkiLCJpYXQiOjE1MjM1MjQxNTksInJvbGVzIjoiYWRtaW4iLCJleHAiOjE1MjM1MjQ1MTl9._YF3oftRNTbq9WCD8Jg1tqcez3cSWoQiDIxMuPmp73o",    
            "name":"admin"   
          } 
}

3、刪除用戶功能鑒權(quán)

?(1)需求:刪除用戶,必須擁有管理員權(quán)限,否則不能刪除。
?(2)前后端約定:前端請(qǐng)求微服務(wù)時(shí)需要添加頭信息Authorization,內(nèi)容為Bearer+空格 +token

(1)修改UserServer的deleteById方法 ,判斷請(qǐng)求中的頭信息,提取token并驗(yàn)證權(quán)限。
    @Autowired
    private HttpServletRequest request;
    
    /**
     * 刪除,必須有admin角色
     * @param id
     */
    public void deleteById(String id) {
        //獲取請(qǐng)求頭
        String header = request.getHeader("Authorization");
        if(header == null && !header.startsWith("Bearer ")){//沒有頭信息,且沒按規(guī)定的格式開頭
            throw new RuntimeException("權(quán)限不足");
        }
        //得到token
        String token = header.substring(7);
         //對(duì)令牌進(jìn)行驗(yàn)證
        try {
            Claims claims = jwtUtil.parseJWT(token);
            //如果是管理員
            if (claims == null && !"admin".equals(claims.get("roles"))){
                throw new RuntimeException("權(quán)限不足");
            }
        }catch (Exception e){
            throw new RuntimeException("令牌不正確");
        }
        userDao.deleteById(id);
    }

4、使用攔截器方式實(shí)現(xiàn)token鑒權(quán)

?? 每個(gè)方法都去寫一段代碼,冗余度太高,不利于維護(hù),那如何做使我們的代碼看起來更清爽呢?我們可以將這段代碼放入攔截器去實(shí)現(xiàn)。

4.1、添加攔截器

?? Spring為我們提供了 import org.springframework.web.servlet.HandlerInterceptor 這個(gè)適配器, 實(shí)現(xiàn)此類,可以非常方便的實(shí)現(xiàn)自己的攔截器。他有三個(gè)方法:
分別實(shí)現(xiàn)預(yù)處理、后處理(調(diào)用了Service并返回ModelAndView,但未進(jìn)行頁面渲 染)、返回處理(已經(jīng)渲染了頁面)

  • 在preHandle中,可以進(jìn)行編碼、安全控制等處理;
  • 在postHandle中,有機(jī)會(huì)修改ModelAndView;
  • 在afterCompletion中,可以根據(jù)ex是否為null判斷是否發(fā)生了異常,進(jìn)行日志記錄。
(1)創(chuàng)建攔截器類。創(chuàng)建 com.springboot.user.interceptor.JwtInterceptor
/**
 * 攔截器
 */
@Component
public class JwtInterceptor implements HandlerInterceptor {

    @Autowired
    private JwtUtil jwtUtil;

    public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
    Object handler) throws Exception {
        System.out.println("經(jīng)過了攔截器");
        return true;
    }

(2)配置攔截器類,創(chuàng)建com.Springboot.user.config.InterceptorConfig
/**
 *  攔截器配置類
 */
@Configuration
public class InterceptorConfig extends WebMvcConfigurationSupport {

    @Autowired
    private JwtInterceptor jwtInterceptor;

    protected void addInterceptors(InterceptorRegistry registry) {
        //注冊(cè)攔截器要聲明攔截的對(duì)象和攔截的路徑
        registry.addInterceptor(jwtInterceptor)
                .addPathPatterns("/**")
                .excludePathPatterns("/**/login/**");
    }
}

4.2 攔截器驗(yàn)證token

(1)修改攔截器類 JwtInterceptor
/**
 *攔截器
 */
@Component
public class JwtInterceptor implements HandlerInterceptor {

    @Autowired
    private JwtUtil jwtUtil;

    public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
    Object handler) throws Exception {
        System.out.println("經(jīng)過了攔截器");
        //無論如何都放行,具體能不能操作還是在具體的操作中判斷;
        //攔截器只是負(fù)責(zé)把請(qǐng)求頭中有token的令牌進(jìn)行解析驗(yàn)證;
        String header = request.getHeader("Authorization");
        if(header != null && header.startsWith("Bearer ")){//有頭信息,且按規(guī)定的格式開頭
            //得到token
            String token = header.substring(7);
            //對(duì)令牌進(jìn)行驗(yàn)證
            try {
                Claims claims = jwtUtil.parseJWT(token);
                //如果是管理員
                if (claims != null && "admin".equals(claims.get("roles"))){
                    request.setAttribute("claims_admin", claims);
                }
                //如果是普通用戶
                if (claims != null && "user".equals(claims.get("roles"))){
                    request.setAttribute("claims_user", claims);
                }
            }catch (Exception e){
                throw new RuntimeException("令牌不正確");
            }
        }
        return true;
    }
}

(2)修改UserService的deleteById方法
    /**
     * 刪除,必須有admin角色
     * @param id
     */
    public void deleteById(String id) {
        Claims claims = (Claims) request.getAttribute("claims_admin");
        if (claims == null){
            throw new RuntimeException("權(quán)限不足");
        }
        userDao.deleteById(id);
    }

5、發(fā)布信息驗(yàn)證Token

步驟:用戶登陸簽發(fā)JWT -------> 攜帶 token 進(jìn)行相應(yīng)的權(quán)限操作

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容