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开启注解
- 在安全配置类开启使用注解
@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
自定义失败处理器,自定义验证策略,自定义动态的权限认证
- 实现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);
}
}
- 修改配置类
authorizationConfig.setJwtUrlsPermissionFailureHandler(new UrlFailureHandler());
自定义验证策略
- 实现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");
}
}
- 修改配置类
httpConfig.addConfigUrlsPermission("home/*").setAuthenizationStrategy(newAuthorizationStrategy);
自定义动态权限认证
- 继承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;
}
}
- 修改配置类
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);
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· winform 绘制太阳,地球,月球 运作规律
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人