jwt(基于token) 鉴权

前言

这个项目是面向jwt的,所以不需要进行登录验证。
这个项目是从https://gitee.com/jefferyeven/jwt-authorization 抽离出来的,
如果想看详细的开发与设计思路可以看一下上面的项目链接。下面我将介绍一些他的的些特性和使用教程。

原理

原理其实是非常简单,主要是通过过滤器进行鉴权,把没有通过权限认证的请求拦截下来,
通过的请求放行。

具体来说:当url来到过滤器时,首先会经过一个鉴权器链(责任链模式)找到能够处理该url的鉴权器
(当url进入鉴权器后,会转成一个字典树。将该字典树与鉴权器的hashmap进行匹配,
找到该与最详细的url所匹配的鉴权策略,找不到进入下一个鉴权器)。

特性

  • 面向jwt
  • 面向权限的(没有面向角色,只面向权限)
  • 多种验证策略(have token/permit all/deny all/have any authority/have all authority)
  • 灵活的设定访问url的权限 (基础鉴权器/注解鉴权器/自定义的鉴权器)
  • 将 验证器 验证策略 鉴权器 都抽象出来便于灵活替换。

使用方式

引入maven

<dependency>
    <groupId>io.github.jefferyeven</groupId>
    <artifactId>jwt_authority</artifactId>
   <version>1.1.0</version>
</dependency>

1. 最简单

例子:https://github.com/jefferyeven/jwt_authority/tree/master/jwt_authority_simple/SimpleUse

1.1 设置jwt的一些配置

在application.properties上添加该项。

#token的过期时间
jwt_token.expire_time = 10000000
#token发布者
jwt_token.isser = test
#token的加密的盐
jwt_token.token_secret = token123
#token放入header的name
jwt_token.token_header_name = token

1.2 extend 配置类 和加上 @Configuration

import io.github.jefferyeven.jwt_authority.config.HttpConfig;
import io.github.jefferyeven.jwt_authority.config.JwtSecurityConfigAdapter;
import org.springframework.context.annotation.Configuration;

@Configuration
public class JwtSecurityConfig extends JwtSecurityConfigAdapter {

    @Override
    public void config(HttpConfig httpConfig) {
        httpConfig.addConfigUrlsPermission("/admin/*").haveAnyAuthority("admin");
        httpConfig.addConfigUrlsPermission("/user/*").haveAnyAuthority("user","admin");
        httpConfig.addConfigUrlsPermission("index/*").permitAll();
        // 如果没有设置我们就默认允许
        httpConfig.getDefaultUrlConfig().permitAll();
    }
}

1.3 发布token

需要用户名,和该用户名所持有的权限就可以发布token

 @RequestMapping("loginAdmin")
    public String loginAdmin(){
        List<String> authority = new ArrayList<>();
        authority.add("admin");
        return JwtSecurityTokenUtil.sign("adminTest",authority);
    }

2. 推荐

例子:https://github.com/jefferyeven/jwt_authority/tree/master/jwt_authority_simple/RecommendedUse

2.1 实现TokenVerifyer(自定义jwt token)

我们可以从header/session/cookie/requset读取token的值,然后验证url所需要的权限和自己有的权限,
具体的实现可以看下方的代码。

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;
import io.github.jefferyeven.jwt_authority.exception.JwtResponseMag;
import io.github.jefferyeven.jwt_authority.exception.JwtSecurityException;
import io.github.jefferyeven.jwt_authority.utils.TokenVerifyer;
import io.github.jefferyeven.jwt_authority.utils.VerifyTokenResult;
import org.springframework.boot.web.servlet.server.Session;
import org.springframework.stereotype.Component;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.util.Date;
import java.util.List;
@Component
public class TokenUtil implements TokenVerifyer {
    public String salt = "fdelsfjdo.243";
    public long expireTime = 100000000;
    String isser = "test";
    private final JWTVerifier verifier = JWT.require(Algorithm.HMAC256(salt)).withIssuer(isser).build();
    @Override
    public VerifyTokenResult verifyToken(HttpServletRequest request, HttpServletResponse response) {
        VerifyTokenResult verifyTokenResult = new VerifyTokenResult();
        // 从head读取token
        String tokenName = "token";
        String token = request.getHeader(tokenName);
//        // 从session读取token
//        HttpSession httpSession = request.getSession();
//        token = (String) httpSession.getAttribute(tokenName);
//        // 从cookie读取token
//        Cookie[] cookies = request.getCookies();
//        for(Cookie cookie:cookies){
//            System.out.println(cookie.getName());
//            if(cookie.getName().equals(tokenName)){
//                token = cookie.getValue();
//                System.out.println(token);
//                break;
//            }
//        }
//        // 从request读取token
//        token = request.getHeader(tokenName);

        if(token==null){
            throw new JwtSecurityException(JwtResponseMag.NoTokenError);
        }
        try {
            DecodedJWT jwt = verifier.verify(token);
            verifyTokenResult.setPassVerify(true);
            Claim authoritiesClaim =  jwt.getClaims().get("authorities");
            if(authoritiesClaim==null){
                return verifyTokenResult;
            }
            List<String> authorities = JSONObject.parseArray(authoritiesClaim.asString(),String.class);
            verifyTokenResult.setAuthorities(authorities);
        } catch (Exception e){
            verifyTokenResult.setPassVerify(false);
        }
        return verifyTokenResult;
    }
    public String sign(String userid, String name, List<String> authorities){
        String token = null;
        try {
            Date expiresAt = new Date(System.currentTimeMillis() + expireTime);
            token = JWT.create()
                    .withIssuer(isser)
                    .withClaim("userid",userid)
                    .withClaim("username", name)
                    .withClaim("authorities", JSON.toJSONString(authorities))
                    .withExpiresAt(expiresAt)
                    // 使用了HMAC256加密算法。
                    .sign(Algorithm.HMAC256(salt));
        } catch (Exception e){
            e.printStackTrace();
        }
        return token;
    }
}

在配置类 设置verifyer

    @Override
    public void config(AuthenizationConfig authorizationConfig){
        authorizationConfig.setStrategyTokenVerifyer(new TokenUtil());
    }

2.2开启注解

  1. 在安全配置类开启使用注解
    @Override
    public void config(AuthenizationConfig authorizationConfig){
        // 开启注解
        authorizationConfig.setUseAnnoation(true);
    }

2.可以修饰类和修饰方法上(只支持加在controller)

@RestController
@RequestMapping("/user")
@NeedAuthorize(authorizeLevel = PermissionLevel.HAVE_ANY_AUTHORITY,authorties = {"admin"})
public class UserController {
    @RequestMapping("/hello")
    public String hello(){
        return "user hello";
    }
    @RequestMapping("needAdmin")
    @NeedAuthorize(authorizeLevel = PermissionLevel.HAVE_ANY_AUTHORITY,authorties = {"admin"})
    public String needAdmin(){
        return "need admin";
    }
}

2.3 设置配置类

@Configuration
public class JwtSecurityConfig extends JwtSecurityConfigAdapter {

    @Override
    public void config(HttpConfig httpConfig) {
        httpConfig.addConfigUrlsPermission("/admin/*").haveAnyAuthority("admin");
        httpConfig.addConfigUrlsPermission("/user/*").haveAnyAuthority("user","admin");
        httpConfig.addConfigUrlsPermission("index/*").permitAll();
        // 如果没有设置我们就默认允许
        httpConfig.getDefaultUrlConfig().permitAll();
    }

    @Override
    public void config(AuthenizationConfig authorizationConfig){
        authorizationConfig.setStrategyTokenVerifyer(new TokenUtil());
        // 开启注解
        authorizationConfig.setUseAnnoation(true);
    }

}

3. 进阶使用

例子:https://github.com/jefferyeven/jwt_authority/tree/master/jwt_authority_simple/advanceUse
自定义失败处理器,自定义验证策略,自定义动态的权限认证

  1. 实现JwtUrlsPermissionFailureHandler接口

自定义失败处理器

public class UrlFailureHandler implements JwtUrlsPermissionFailureHandler {
    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, Exception e) throws ServletException, IOException {
        System.out.println("出现了错误");
        e.printStackTrace();
        request.setAttribute("exception",e);
        // 跳转到处理错误的页面
        request.getRequestDispatcher("/index/error").forward(request,response);
    }
}
  1. 修改配置类
    authorizationConfig.setJwtUrlsPermissionFailureHandler(new UrlFailureHandler());

自定义验证策略

  1. 实现authorizationStrategy接口
@Component
public class NewAuthorizationStrategy implements authorizationStrategy {
    @Autowired
    TokenUtil tokenUtil;
    @Override
    public boolean passauthorization(HttpServletRequest request, HttpServletResponse response, UrlPermission urlPermission) throws Exception {
        // 从header读取token
        VerifyTokenResult verifyTokenResult = tokenUtil.verifyToken(request,response);
        if(!verifyTokenResult.isPassVerify()){
            return false;
        }
        // 这里的验证规则是有admin就直接通过
        return verifyTokenResult.getAuthorities().contains("vip");
    }
}
  1. 修改配置类
    httpConfig.addConfigUrlsPermission("home/*").setAuthenizationStrategy(newAuthorizationStrategy);

自定义动态权限认证

  1. 继承AbstractAuthenization
@Component
public class DynamicAuthorization extends AbstractAuthenization {
    @Autowired
    UrlAuthoritiesMapper urlAuthoritiesMapper;
    @Autowired
    TokenUtil tokenUtil;
    @Override
    public AuthenizationState passAuthenizate(HttpServletRequest request, HttpServletResponse response) throws Exception {
        System.out.println(request.getRequestURI());
        UrlAuthorities urlAuthorities = urlAuthoritiesMapper.getUrlAuthoritiesFromUrl(request.getRequestURI());
        if(urlAuthorities==null){
            return AuthenizationState.UnAuthenizateState;
        }
        VerifyTokenResult verifyTokenResult = tokenUtil.verifyToken(request,response);
        if(!verifyTokenResult.isPassVerify()){
            throw new JwtSecurityException(JwtResponseMag.TokenError);
        }
        List<String> authortities = JSON.parseObject(urlAuthorities.getAuthorities(),List.class);
        for(String s:authortities){
            if(verifyTokenResult.getAuthorities().contains(s)){
                return AuthenizationState.PassState;
            }
        }
        return AuthenizationState.UnAuthenizateState;
    }
}
  1. 修改配置类
    authorizationConfig.addAuthenization(dynamicAuthorization,1);

总的鉴权器配置

@Configuration
public class JwtSecurityConfig extends JwtSecurityConfigAdapter {
    @Autowired
    DynamicAuthorization dynamicAuthorization;
    @Autowired
    NewAuthorizationStrategy newAuthorizationStrategy;
    @Override
    public void config(HttpConfig httpConfig) {
        httpConfig.addConfigUrlsPermission("/admin/*").haveAnyAuthority("admin");
        httpConfig.addConfigUrlsPermission("/user/*").haveAnyAuthority("user","admin");
        httpConfig.addConfigUrlsPermission("index/*").permitAll();
        httpConfig.addConfigUrlsPermission("home/*").setAuthenizationStrategy(newAuthorizationStrategy);
        // 如果没有设置我们就默认允许
        httpConfig.getDefaultUrlConfig().permitAll();
    }

    @Override
    public void config(AuthenizationConfig authorizationConfig){
        authorizationConfig.setStrategyTokenVerifyer(new TokenUtil());
        // 开启注解
        authorizationConfig.setUseAnnoation(true);
        // 设置失败处理器
        authorizationConfig.setJwtUrlsPermissionFailureHandler(new UrlFailureHandler());
        // 设置自定义的鉴权器
        authorizationConfig.addAuthenization(dynamicAuthorization,1);
    }

}
posted @   度一川  阅读(501)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· winform 绘制太阳,地球,月球 运作规律
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
点击右上角即可分享
微信分享提示