SpringBoot整合jwt+shiro

话不多说,直接上代码

引入依赖如下的依赖,springboot不造怎么构建,请先把springboot玩熟了在回来看吧。

		<!-- JWT依赖 -->
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <version>0.7.0</version>
        </dependency>
        <dependency>
            <groupId>com.auth0</groupId>
            <artifactId>java-jwt</artifactId>
            <version>3.4.0</version>
        </dependency>
        <!--整合shiro-->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>1.4.0</version>
        </dependency>

集成JWT

配置类与工具类写在一起,有些人喜欢分开写,看个人呗。

package com.emmmya.harin.config.security.jwt;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.util.Date;

/**
 * JWT的token,区分大小写
 */
@Component
public class JwtConfig {
    @Value("${config.jwt.secret}")
    private String secret;
    @Value("${config.jwt.expire:3600}")
    private long expire;
    @Value("${config.jwt.header}")
    private String header;

    /**
     * 生成token
     * @param subject
     * @return
     */
    public String createToken (String subject){
        //System.out.println(split);
        Date nowDate = new Date();
        Date expireDate = new Date(nowDate.getTime() + expire * 1000);//过期时间

        return Jwts.builder()
                .setHeaderParam("typ", "JWT")
                .setSubject(subject)
                .setIssuedAt(nowDate)
                .setExpiration(expireDate)
                .signWith(SignatureAlgorithm.HS512, secret)
                .compact();
    }

    /**
     * 获取token中注册信息
     * @param token
     * @return
     */
    public Claims getTokenClaim (String token) {
        try {
            return Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody();
        }catch (Exception e){
            e.printStackTrace();
            return null;
        }
    }
    /**
     * 验证token是否过期失效
     * @param expirationTime
     * @return true表示过期,false表示没过期。
     */
    public boolean isTokenExpired (Date expirationTime) {
        return expirationTime.before(new Date());
    }

    /**
     * 获取token失效时间
     * @param token
     * @return
     */
    public Date getExpirationDateFromToken(String token) {
        return getTokenClaim(token).getExpiration();
    }
    /**
     * 获取用户名从token中
     */
    public String getUsernameFromToken(String token) {
        return getTokenClaim(token).getSubject();
    }

    /**
     * 获取jwt发布时间
     */
    public Date getIssuedAtDateFromToken(String token) {
        return getTokenClaim(token).getIssuedAt();
    }

    // --------------------- getter & setter ---------------------

    public String getSecret() {
        return secret;
    }
    public void setSecret(String secret) {
        this.secret = secret;
    }
    public long getExpire() {
        return expire;
    }
    public void setExpire(long expire) {
        this.expire = expire;
    }
    public String getHeader() {
        return header;
    }
    public void setHeader(String header) {
        this.header = header;
    }
}

这类里面有依赖注入,我也贴出来给大家看看,secret是我加密过的,不直接展示出来(加密技术是:jasypt,小伙子们可以了解了解)

jwt:
    # 加密密钥
    secret: ENC(3/pMc6HNFuihXbmxwbCgcMyxuiPT8Z9T4u7I9feygcRRXDKkDQNr4yUGpkTP4UoubwLtrY5sW40PS0qXzYk1PQ==)
    # token有效时长(秒)
    expire: 3600
    # header 名称
    header: accept-token

这个对这三个参数做解释:

secret:JWT生成token的加密的密钥。

expire:生token的有时长

header:前端保存token的key名

那么,token的一个整合就弄好了。可以先写个接口来玩一玩了。

@Slf4j
@RestController
@Api("使用shiro+jwt来控制登录")
public class TokenController {
	//注入生成token的工具类
	@Autowired
	JwtConfig jwtConfig;
	/**
     * 用户登录接口
     * @return
     */
    @RequestMapping (value = "/user/login")
     public Result<Object> login(@ReuqestBody User user){
     String token = JwtConfig.createToken(username);
     return ResultUtils.success(token);
}

在这里插入图片描述

{
	code:200,
	message:"success",
	result:"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJIYXJpbiIsImlhdCI6MTU5MDEzODM0OCwiZXhwIjoxNTkwMTQxOTQ4fQ.-FJvZn6P-aOxJFyUad_nLds1zi50ib_cTT8ZEx3227c5MuP53_DQcs0H1sWwFEiFFEXUGGLnC4SDcXXh-I1k9A"
}

result里的数据就是token。这个格式的数据如果不清楚的,请先了解 什么是jwt,戳下面⬇⬇⬇⬇
什么是jwt??

前面我只是说集成进来springboot中,但没有说着运用到项目里了。

想想jwt的作用,那就是作为登录令牌使用。那就是在每次请求中,都需要浏览器传这个参数给后台,辨认该请求时登录过的了(也可以用于单点登录)。

那么,后台需要前端传过来token并校验token有效性。既然每个请求都需要做校验。从学过的技术与结合当前结合的技术来想,可以考虑,过滤器,拦截器两种方式。

把jwt结合到项目中

拦截器写法:

package com.emmmya.harin.interceptor;

import com.emmmya.harin.common.constant.RedisConstant;
import com.emmmya.harin.common.utils.FileNameUtils;
import com.emmmya.harin.common.utils.HResourcesUtils;
import com.emmmya.harin.common.utils.RedisUtil;
import com.emmmya.harin.common.utils.ShiroUtils;
import com.emmmya.harin.config.security.jwt.JwtConfig;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.SignatureException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import org.thymeleaf.util.StringUtils;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;

/**
 * 因为一开始没有redis。所以这个过期时间配置在toekn里面。
 */
@Component
public class JwtTokenInterceptor extends HandlerInterceptorAdapter {
	@Value("${jwt.header}")
	private String header;
    @Override
    public boolean preHandle(HttpServletRequest request,
                             HttpServletResponse response,
                             Object handler) throws SignatureException, IOException, ServletException {
        /** 这两个地址,直接放行 */
        String uri = request.getRequestURI();
        System.out.println("JwtTokenInterceptor:"+uri);
        if ("/login".equals(uri) || "/logout".equals(uri) ){
            return true ;
        }
        /** Token 验证 */
        //在请求头中获取token,请求头的名字就是上面配置文件的header值
           String   token = request.getHeader(jwtConfigs.getHeader());
        if(StringUtils.isEmpty(token)){
            throw new SignatureException(jwtConfigs.getHeader()+ "不能为空");
        }

        Claims claims = null;
        try{
            claims = jwtConfigs.getTokenClaim(token);
            if(claims == null || jwtConfigs.isTokenExpired(claims.getExpiration())){
               throw new SignatureException(jwtConfigs.getHeader() + "失效,请重新登录。");
                 }
        }catch (Exception e){
            throw new SignatureException(jwtConfigs.getHeader() + "失效,请重新登录。");
        }

        /** 设置 identityId 用户身份ID */
        request.setAttribute("identityId", claims.getSubject());
        return true;
    }
}

写好拦截器后,需要把拦截器注册到spring中

package com.emmmya.harin.config;

import com.emmmya.harin.common.utils.ShiroUtils;
import com.emmmya.harin.interceptor.CheckTokenInterceptor;
import com.emmmya.harin.interceptor.JwtTokenInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.LocaleResolver;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.i18n.LocaleChangeInterceptor;
import org.springframework.web.servlet.i18n.SessionLocaleResolver;

import java.util.Locale;

@Configuration
public class JwtWebConfig implements WebMvcConfigurer {
    public void addInterceptors(InterceptorRegistry registry) {
        //将jwt拦截器注册到WebMvc里。
     	//拦截所有的请求,所有请求都需要
     	registry.addInterceptor(jwtTokenInterceptor).addPathPatterns("/**");
}

好了,写个接口来测试下。

@Slf4j
@RestController
@Api("使用shiro+jwt来控制登录")
public class TokenController {
	//注入生成token的工具类
	@Autowired
	JwtConfig jwtConfig;
	/**
     * 用户登录接口
     * @return
     */
    @RequestMapping (value = "/user/login")
		public Result<Object> login(@ReuqestBody User user){
     		String token = JwtConfig.createToken(username);
     		return ResultUtils.success(token);
	@RequestMapping(value ="testToken")
		public Result<Object> testToken(){
			return ResultUtils.success("你有token呀?NB喔。");
	}
}
使用postman测试:

不携带Token请求时候。
在这里插入图片描述
这里就会抛出异常,至于异常处理,看你想怎么写了,写个异常页面单独处理也是可以的。

携带Token请求

在这里插入图片描述
在请求头上带上token后再请求。就发现放回的就是接口写好的字符串了。
PS:这个返回接口是单独写好的一个类。你们返回的结果可不一定跟我一样。但是只要看到接口返回的接口就好了。

集成shiro(配合jwt一起使用)

未完,待续.....
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值