使用JWT生成token实现权限验证

这篇具有很好参考价值的文章主要介绍了使用JWT生成token实现权限验证。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

流程

        点击登录按钮,后端验证账号密码是否通过,如果通过则生成token,把token发送给前端,前端保存到cookie(前后端分离是不能使用保存session,因为每次发送ajax请求响应后都会断开服务器,就会导致session生命周期就销毁掉,然后再发送请求时再重新连接服务器,session已经不存在了),之后访问受限资源就需要取cookie拿到token,然后作为参数(放在请求头更安全)发送给后端,后端验证token。

Jwt介绍

Jwt是由三部分组成的字符串(header头部,payload载荷,signature签名)

头部:用于描述关于该 JWT 的最基本的信息,例如其类型以及签名所用的算法等。这也可以被表示成一个 JSON 对象。例如:
{
    "typ": "JWT",
    "alg": "HS256"
}
载荷:其实就是自定义的数据,一般存储用户 Id,过期时间等信息。也就是 JWT 的核心所在,因为这些数据就是使后端知道此 token 是哪个用户已经登录的凭证。而且这些数据是存在 token 里面的,由前端携带,所以后端几乎不需要保存任何数据。
例如:
{
    "uid": "xxxxidid", //用户id
    "exp": "12121212" //过期时间
}
签名:1.头部和载荷 各自base64加密后用.连接起来,然后就形成了 xxx.xx 的前两段 token。2.最后一段 token 的形成是,前两段加入一个密匙用 HS256 算法或者其他算法加密形成。3. 所以 token3 段的形成就是在签名处形成的。

将这三部分用.连接成一个完整的字符串,构成了最终的jwt

一、添加依赖

        //提供JWT的java类
        <dependency>
            <groupId>com.auth0</groupId>
            <artifactId>java-jwt</artifactId>
            <version>3.10.3</version>
        </dependency>
        //提供JWT算法
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <version>0.9.1</version>
        </dependency>

二、给登录按钮添加单击事件@click="doSubmit"。给账号文本框密码文本框都添加@blur="checkInfo"事件。发送请求,接收响应信息

重点代码:  setCookieValue("token",vo.msg) 调用自定义方法setCookieValue把token放到cookie 

<script type="text/javascript">
            var baseUrl = "http://localhost:8080/";
			var vm = new Vue({
				el:"#container",
				data:{
					username:"",
					password:"",
					tips:"",
					colorStyle:"color:red",
					isRight:false,
				},
				methods:{
					doSubmit:function(){
						if(vm.isRight){
							var url = baseUrl+"user/login";
							axios.get(url,{
								params:{
									username:vm.username,
									password:vm.password
								}
							}).then((res)=>{
								//res.data 才表示接口返回的数据
								var vo = res.data;
								
								if(vo.code == 10000){
									//如果登录成功,就把token存储到cookie,后端是把token放在msg里
									setCookieValue("token",vo.msg); 
									window.location.href="index.html";
								}else{
									vm.tips = "登录失败,账号或密码错误!"
								}
									
							});
							
						}else{
							vm.tips = "请正确输入帐号和密码!";
						}
					},
					checkInfo:function(){
						if(vm.username == ""){
							vm.tips = "请输入帐号!";
							vm.isRight = false;
						}else if(vm.username.length<8 || vm.username.length>20){
							vm.tips = "账号长度必须为8-20个字符!";
							vm.isRight = false;
						}else{
							//账号合法,校验密码
							if(vm.password == ""){
								vm.tips = "请输入密码!";
								vm.isRight = false;
							}else if(vm.password.length<6 || vm.password.length>16){
								vm.tips = "密码长度必须为6-16个字符!";
								vm.isRight = false;
							}else{
								vm.tips ="";
								vm.isRight = true;
							}
						}
					}
				}
			});
			

		</script>

三、Controller接收请求

@GetMapping("/user/login")
    public ResultVO login(@RequestParam("username") String name,
                          @RequestParam("password") String pwd){
        return userService.checkLogin(name,pwd);
    }

四、Service和ServiceImpl处理业务、生成token

public interface UserService {

    public ResultVO checkLogin(String name, String pwd);
}
@Service
@Scope("singleton")//singleton单例模式,全局有且仅有一个实例
public class UserServiceImpl implements UserService {
    @Resource
    private UsersMapper usersMapper;

   @Override
    public ResultVO checkLogin(String name, String pwd) {
        //使用tkmapper查询user 你们用自己写的mapper也可以
        Example example = new Example(Users.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("username",name);

        List<Users> users = usersMapper.selectByExample(example);
        if(users.size()==0){
            return new ResultVO(10001,"登录失败,用户名不存在",null);
        }else {
            Users user = users.get(0);
            String md5Pwd = MD5Utils.md5(pwd);
            // 数据库密码是MD5加密过的,MD5算法又不可逆,所以只能把登录密码加密后去和数据库的密码比对
            if(user.getPassword().equals(md5Pwd)){
                //如果登录成功,生成token

                JwtBuilder builder = Jwts.builder();

                HashMap<String,Object> map = new HashMap<>();
                map.put("key1","value1");
                map.put("key2","value2");

                String token = builder.setSubject(name)                     //载荷部分,主题,就是token中携带的数据,这里把用户名放进去
                        .setIssuedAt(new Date())                            //设置token的生成时间
                        .setId(users.get(0).getUserId() + "")               //设置用户id为token  id      ''是因为用户id是int类型,需要转换为字符串类型
                        .setClaims(map)                                     //map中可以存放用户的角色权限信息
                        .setExpiration(new Date(System.currentTimeMillis() + 24*60*60*1000)) //设置token过期时间,当前时间加一天就是时效为一天过期
                        .signWith(SignatureAlgorithm.HS256, "ycj123456")     //签名部分,设置HS256加密方式和加密密码,ycj123456是自定义的密码
                        .compact();
                return new ResultVO(10000,token,user);//把token封装到ResultVO传到前端。
            }else {
                return new ResultVO(10001,"密码错误",null);
            }
        }
    }
}

五、MD5、返回的工具类

package com.ycj.utils;

import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

//MD5 生成器
public class MD5Utils {
	public static String md5(String password){
		//生成一个md5加密器
		try {
			MessageDigest md = MessageDigest.getInstance("MD5");
			//计算MD5 的值
			md.update(password.getBytes());
			//BigInteger 将8位的字符串 转成16位的字符串 得到的字符串形式是哈希码值
			//BigInteger(参数1,参数2) 参数1 是 1为正数 0为零 -1为负数
			return new BigInteger(1, md.digest()).toString(16);
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		}
		return null;
	}
}
public class ResStatus {

    public static final int OK=10000;
    public static final int NO=10001;

    public static final int LOGIN_SUCCESS = 2000;  //认证成功
    public static final int LOGIN_FAIL_NOT = 20001; //用户未登录
    public static final int LOGIN_FAIL_OVERDUE = 20002; //用户登录失效

}
@Data
@AllArgsConstructor
@NoArgsConstructor
public class ResultVO {
    private int code;
    private String msg;
    private Object data;
}

六、Dao查询用户信息

这里是使用tkMapper,selectByExample()就是它提供的,你们也可以自己写mapper

public interface UsersMapper extends Mapper<User>,MySqlMapper<User> {
//继承了Mapper<T>,MySqlMapper<T>就不用写dao和mapper了
}

七、从cookie中存取token

//cookie只能存放键值对
var operator = "=";
//window.document.cookie可以拿到cookie所有的key=value;形式的字符串。所以从cookie拿值,遍历cookie的所有key,直到key等于keyStr,
//就可以拿到对应的值,例如我们要拿名为token的key,调用方法getCookieValue(token)就可以拿到key为token的值(value)
function getCookieValue(keyStr){
	var value = null;
	var s = window.document.cookie;
	var arr = s.split("; ");
	for(var i=0; i<arr.length; i++){
		var str = arr[i];
		var k = str.split(operator)[0];
		var v = str.split(operator)[1];
		if(k == keyStr){
			value = v;
			break;
		}
	}
	return value;
}
//往cookie中设置格式:document.cookie = key=value,例如token=fohweoif2n334023noi2r
function setCookieValue(key,value){
	document.cookie = key+operator+value;
}

八、携带token访问受限资源示例,发送请求,接收响应信息

重点代码:var token = getCookieValue("token");    headers:{token:token  //访问受限资源必须把token传到后端校验},

<script type="text/javascript">
			var vm = new Vue({
				el:"#container",
				data:{
					token:null,
				},
                created:function(){
					var token = getCookieValue("token");
					if(token == null){
						var loginUrl = "login.html?tips=请先登录!&returnUrl=shopcart.html";//returnUrl是登录成功后重新返回这个页面的url
						window.location.href = encodeURI(loginUrl);
					}else{
						//请求当前用户的购物车记录
						this.token = token;//this.token是data中的token
						var userId = getCookieValue("userId");
						var url = baseUrl+"shopcart/list";
						axios({
							url:url,//写受限资源的url
							method:"get",
							headers:{
								token:token  //访问受限资源必须把token传到后端校验
							},
							params:{
								userId:userId  //这里userId是我访问受限资源所需要的,你们根据自己的需求
							}
						}).then((res)=>{
							console.log(res.data);
							if(res.data.code==20002 || res.data.code==20001){
								//token过期或未登录
								var loginUrl = "login.html?tips=请先登录!&returnUrl=shopcart.html";
								window.location.href = encodeURI(loginUrl);
							}else{
								//请求成功,拿到数据,进行渲染页面
								this.shopcarts = res.data.data;
							}
						});
					}
				},
			});
		</script>

九、设置拦截器

如果受限资源有多个,我们可以设置拦截器去校验token,就不用每次都去校验一次

配置拦截路径

@Configuration
public class InterceptorConfig implements WebMvcConfigurer {

    @Autowired
    private CheckTokenInterceptor checkTokenInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(checkTokenInterceptor)
                .addPathPatterns("/shopcart/**")
                .addPathPatterns("/orders/**")
                .addPathPatterns("/useraddr/**")
                .addPathPatterns("/user/check");
}

拦截并解析token

@Component
public class CheckTokenInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //关于浏览器的请求预检.在跨域的情况下,非简单请求会先发起一次空body的OPTIONS请求,称为"预检"请求,用于向服务器请求权限信息,等预检请求被成功响应后,才发起真正的http请求。
        String method = request.getMethod();
        if("OPTIONS".equalsIgnoreCase(method)){
            return true;
        }
//        String token = request.getParameter("token");放入params才能用这个,放hearder用getHearder
        String token = request.getHeader("token");
        if(token == null){
            ResultVO resultVO = new ResultVO(ResStatus.LOGIN_FAIL_NOT, "请先登录!", null);
            doResponse(response,resultVO);
        }else{
            try {
                JwtParser parser = Jwts.parser();
                parser.setSigningKey("ycj123456"); //解析token的SigningKey必须和生成token时设置密码一致
                //如果token检验通过(密码正确,有效期内)则正常执行,否则抛出异常
                Jws<Claims> claimsJws = parser.parseClaimsJws(token);
                return true;//true就是验证通过,放行
            }catch (ExpiredJwtException e){
                ResultVO resultVO = new ResultVO(ResStatus.LOGIN_FAIL_OVERDUE, "登录过期,请重新登录!", null);
                doResponse(response,resultVO);
            }catch (UnsupportedJwtException e){
                ResultVO resultVO = new ResultVO(ResStatus.LOGIN_FAIL_NOT, "Token不合法,请自重!", null);
                doResponse(response,resultVO);
            }catch (Exception e){
                ResultVO resultVO = new ResultVO(ResStatus.LOGIN_FAIL_NOT, "请先登录!", null);
                doResponse(response,resultVO);
            }
        }
        return false;
    }
    //没带token或者检验失败响应给前端
    private void doResponse(HttpServletResponse response,ResultVO resultVO) throws IOException {
        response.setContentType("application/json");
        response.setCharacterEncoding("utf-8");
        PrintWriter out = response.getWriter();
        String s = new ObjectMapper().writeValueAsString(resultVO);
        out.print(s);
        out.flush();
        out.close();
    }

}

如果token校验通过,返回true,拦截器会放行,可以访问受限资源。否则,使用doResponse(response,resultVO)响应信息给前端页面。文章来源地址https://www.toymoban.com/news/detail-403470.html

到了这里,关于使用JWT生成token实现权限验证的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 如何使用 NestJS 集成 Passort 和 JWT Token 实现 HTTP 接口的权限管理

    💡 如果你不希望其他人可以随意进出你的房子,那么你需要给你的房子上个锁。 开发一个接口很容易,开发一个具有安全性的接口却不容易。成熟的后端服务项目最注重的一点就是如何保护系统的数据安全,不能让用户无脑的访问操作所有的数据,这是不合理更是极度危险

    2024年01月22日
    浏览(43)
  • 在springBoot中使用JWT实现1.生成token,2.接收前端token进行身份认证,3.通过token获取对象信息

    第一步:引入依赖 第二步:创建工具类 在until包下创建TokenUntil类,用于生成token 利用id,和password作为参数生成token JWt为这个包下的对象 第三步:token使用 在向前端返回的数据对象中添加token属性  是serve层中调用工具类方法将生成的token放到返回的数据中 注意:这里获取到

    2024年02月04日
    浏览(68)
  • 【SpringBoot】1、SpringBoot整合JWT实现Token验证

    单点登录(Single Sign On), 简称为 SSO , 是目前比较流行的企业业务整合的解决方案之一. SSO的定义:在多个应用系统中, 用户只需要登录一次就可以访问所有相互信任的应用系统, 企业间需要相互授信 众所皆知, HTTP是 无状态的协议 , 这意味着 服务器无法确认用户的信息。 于是乎,

    2024年02月03日
    浏览(73)
  • SpringBoot(九)jwt + 拦截器实现token验证

        前面两篇文章的过滤器和拦截器,我们都提到过可以做诸如权限验证的事情。http/https是无状态的协议,当用户访问一个后端接口时,如何判断该用户有没有权限?当然,可以使用账号+密码去验证。但是,如果使用账号和密码,需要频繁访问数据库,很明显,会带来一些

    2024年02月04日
    浏览(81)
  • Springboot实现websocket(连接前jwt验证token)

    用户连接服务器weksocket前,需经过jwt的token验证(token中包含账号信息),验证合法后,才可以于服务器正常交互。 一、配置依赖(pom.xml) 二、因为springboot的websocket连接时不会显示header信息,也就无法拿到cookie中的token信息,需要在连接前处理,新建一个WebSocketConfig.class,在

    2024年02月03日
    浏览(82)
  • 构建强大的Python后端分离应用:使用Token实现安全身份验证和权限控制

    使用Python构建一个强大的后端分离应用,通过使用Token实现安全的身份验证和灵活的权限控制。 什么是前后端分离: 前后端分离是一种软件架构模式,它将应用程序的前端(用户界面)和后端(业务逻辑和数据处理)分离开发和部署。在前后端分离架构中,前端和后端是独立

    2024年02月03日
    浏览(64)
  • token和JWT token区别、登录安全、页面权限、数据权限、单点登录

     直接区别: token需要查库验证token 是否有效,而JWT不用查库或者少查库,直接在服务端进行校验,并且不用查库。因为用户的信息及加密信息在第二部分payload和第三部分签证中已经生成,只要在服务端进行校验就行,并且校验也是JWT自己实现的。     JWT是json web token缩写。

    2023年04月09日
    浏览(49)
  • 04 动力云客之登录后获取用户信息+JWT存进Redis+Filter验证Token + token续期

    非常好实现. 只要新建一个controller, 并调用SS提供的Authentication对象即可 未登录状态下可以直接访问 api/login/info吗? 不可以. 因为在安全配置类已经写明了, 仅登陆界面允许任何人访问, 其他所有界面都需要认证 由于未写JWT, 默认使用Session 保存会话, ???好像不对 因此只要我们先

    2024年02月21日
    浏览(60)
  • 封装hutool工具生成JWT token

    这一步非常重要,否则部署项目会发生JCE cannot authenticate the provider BC BouncyCastle类是一个加密的第三方类,关闭它使用jdk自带的加密算法 GlobalBouncyCastleProvider.setUseBouncyCastle(false);

    2024年02月15日
    浏览(93)
  • 基于NodeJs+Express+MySQL 实现实现登录注册接口+token生成与解析验证+跨域-CORS

    目录 一、express是什么? 二、安装 express 三、安装Mysql 四、安装 nodemon 实现项目热更新 五、这里先了解下express的post get delete接口 post接口说明: get接口说明 :  DELETE 接口 六、注册功能 1、流程分析 校验表单数据是否合法 检测用户名是否占用 密码加密处理 插入新用户 2、

    2024年02月11日
    浏览(48)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包