这篇文章主要讲解了“JTW怎么实现认证与授权”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“JTW怎么实现认证与授权”吧!
是为了在网络应用环境中传递声明而执行的一种基于json的开放标准。特别适合分布式站点的单点登录场景。jwt的声明一般被用来在身份提供者和服务提供者之间传递被认证的用户身份信息,以便于从服务器获取资源,也可以增加一些额外的其他业务逻辑所用到的生命信息。
JWT由三部分组成,详情如下图:
header:头部
alg表示签名的生成算法。 typ表示这个令牌(token)的类型(type),JWT 令牌统一写为JWT。
{
"alg":"HS256",
"typ":"JWT"
}
payload:有效载荷
可选参数: iss: 签发者 sub: 面向用户 aud: 接收者 iat(issued at): 签发时间 exp(expires): 过期时间 nbf(not before):不能被接收处理时间,在此之前不能被接收处理 jti:JWT ID为web token提供唯一标识
{
"sub":"123456",
"exp":"1564641412"
}
signature:签名
以header和payload生成的签名,防止header和payload被篡改。这里需要指定一个密码(secret)。该密码仅仅为保存在服务器中,并且不能向用户公开, 解析时需要匹配密码(secret)才能解析成功。
String signature = HMACSHA512(base64UrlEncode(header)+"."+
base64UrlEncode(payload),
secret);
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.0</version>
</dependency>
需拦截除登录外所有接口,并开放静态路径
@Configuration
public class WebConfig extends WebMvcConfigurationSupport {
@Autowired
private JwtInterceptor jwtInterceptor;
/**
* 配置静态资源
* @param registry
*/
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/**")
.addResourceLocations("classpath:/static/");
registry.addResourceHandler("/swagger-ui.html")
.addResourceLocations("classpath:/META-INF/resources/");
registry.addResourceHandler("/webjars/**")
.addResourceLocations("classpath:/META-INF/resources/webjars/");
super.addResourceHandlers(registry);
}
/**
* 注册拦截器
* @param registry
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 添加拦截的请求,并排除几个不拦截的请求
registry.addInterceptor(jwtInterceptor).addPathPatterns("/**")
.excludePathPatterns("/loginController/loginSystem","/swagger-ui.html",
"/static/**","/swagger-resources/**","/webjars/**",");
}
@Component
public class JwtInterceptor extends HandlerInterceptorAdapter {
@Autowired
private JwtTokenConfig jwtTokenConfig;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String header = Constant.getContentProperties().getStringProperty("header");
//获取请求token
String reqToken = getJwt(request);
if (jwtTokenConfig.validateJwtToken(reqToken)) {
return true;
}
return false;
}
/**
* 获取并返回token信息
* @param request
* @return
*/
private String getJwt(HttpServletRequest request) {
//从header中获取
String authHeader = request.getHeader("Authorization");
String header = Constant.getContentProperties().getStringProperty("header");
if (StringUtils.startsWith(authHeader, header)) {
authHeader = authHeader.replace(header+" ", "");
}
return authHeader;
}
配置类用于生成、解析、校验Token。由于业务需求,token过期后将派发新的token。
@Configuration
public class JwtTokenConfig {
private static final Logger logger = LoggerFactory.getLogger(JwtTokenConfig.class);
@Autowired
private JwtTokenMapper jwtTokenMapper;
//读取配置文件信息
private String expire = Constant.getContentProperties().getStringProperty("expire");
private String secret = Constant.getContentProperties().getStringProperty("secret");
private String header = Constant.getContentProperties().getStringProperty("header");
/**
* 生成token
* @param subject
* @return
*/
public String generateToken(String subject) {
//设置过期时间
Date expireDate = new Date(System.currentTimeMillis() + 1000 * Long.parseLong(expire));
//组建header
Map<String, Object> headMap = new HashMap<>();
headMap.put("alg", SignatureAlgorithm.HS256.getValue());
headMap.put("typ", "JWT");
//自定义组件
Map<String, Object> claims = new HashMap<>();
claims.put("created", DateUtil.formatDate(new Date(),DateUtil.YEAR_TO_SECOND));
String access_token = Jwts.builder().setHeader(headMap)
.signWith(SignatureAlgorithm.HS512, secret)
.setClaims(claims)
//面向用户
.setSubject(subject)
//过期时间
.setExpiration(expireDate)
//生成token
.compact();
//刷新数据库中token信息
refreshToken(subject, access_token, expireDate);
logger.info(subject+" 生成后的token:"+access_token);
return access_token;
}
/**
* 获得签名信息
* @param token
* @return
*/
public Claims getClaimsFromToken(String token) {
Claims claims = null;
try {
claims = Jwts.parser()
.setSigningKey(secret)
.parseClaimsJws(token)
.getBody();
logger.info("解析token结果:"+claims);
} catch (ExpiredJwtException e) {
//token过期创建并返回一个新token
logger.info("token过期,正在创建新token\n");
JwtToken jwtToken = jwtTokenMapper.selectByToken(token);
if(jwtToken != null){
String newToken = generateToken(jwtToken.getUserCode());
claims = Jwts.parser()
.setSigningKey(secret)
.parseClaimsJws(newToken)
.getBody();
logger.info("解析token结果:"+claims);
} else{
logger.info("token无效");
}
} catch (Exception e){
logger.info("解析异常");
}
return claims;
}
/**
* token校验
* @param token
* @return
*/
public boolean validateJwtToken(String token){
if(StringUtils.isNotBlank(token)){
//获得token中signature信息,并验证过期时间
Claims claims = getClaimsFromToken(token);
JwtToken jwtToken = jwtTokenMapper.selectByUserCode(claims.getSubject());
HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
if(jwtToken == null || jwtToken.getJwtId() <= 0){
logger.info("token无效");
}
//返回信息中将token添加至header中
response.setHeader("Authorization",header+" "+jwtToken.getToken());
return true;
} else{
logger.info("token为空");
}
}
/**
* 刷新数据库中token信息
* @param subject
* @param access_token
* @param expireDate
*/
public void refreshToken(String subject, String access_token, Date expireDate){
//数据库中存储数据
jwtTokenMapper.deleteByUserCode(subject);
JwtToken jwtToken = new JwtToken();
jwtToken.setUserCode(subject);
jwtToken.setToken(access_token);
jwtToken.setCreateTime(new Date());
jwtToken.setExpireTime(expireDate);
jwtTokenMapper.insertSelective(jwtToken);
}
}
拦截器中出现异常后,通常会使用系统默认方式返回,若想自定义返回json,则需要使用异常拦截器。
@ControllerAdvice
public class ExceptionInterceptor {
@ExceptionHandler(value = Exception.class)
@ResponseBody
public Map<String, Object> allExceptionHandler(Exception e){
Map<String, Object> resultMap = new HashMap<>(2);
if(e instanceof Exception){
resultMap.put("code", "500");
resultMap.put("msg", e.getMessage());
}
return resultMap;
}
}
感谢各位的阅读,以上就是“JTW怎么实现认证与授权”的内容了,经过本文的学习后,相信大家对JTW怎么实现认证与授权这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是亿速云,小编将为大家推送更多相关知识点的文章,欢迎关注!
亿速云「云服务器」,即开即用、新一代英特尔至强铂金CPU、三副本存储NVMe SSD云盘,价格低至29元/月。点击查看>>
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。
原文链接:https://my.oschina.net/u/4176955/blog/3082482