spring boot+jwt 权限验证

上周看了一下jwt以前公司的开发都是使用session共享的方法。现在主流的两种方式一种是把登录信息保存在服务器,另一种则是把信息保存在客户端。在使用session 存储的时候会遇到很多的问题,随着项目越来越多工作量会变得越来越大。现在公司要开始一个新的项目,索性就开始使用jwt,数据保存在客户端每一次请求都回传给服务器验证一下。

本文分为两部分第一部分简单介绍一下JWT,第二部分简单介绍一下使用spring boot+jwt构建一个项目。

一、什么是JWT?

JWT全程JSON Web tokens 主要由 三部分组成通过“.”分割开,三部分分别是Header、Payload、Signature因此一个完成的JWT经典结构体应该是xxxx.yyyy.zzzzz

1.Header (头)

头部是一个包括了两部分的JSON 一部分是签名的算法(alg)通常使用HS256或者RSA,这里基本上都是使用HS256,还有一个部分是签名类型(typ)即JWT

例如:

{
  "alg": "HS256",
  "typ": "JWT"
}

然后把这个JSON Base64Url,形成第一部分。

2.Payload (数据)

第二部分也是一个JSON对像,官方提供了几个数据字段 iss (issuer):签发人、exp (expiration time):过期时间、sub (subject):主题、aud (audience):受众、nbf (Not Before):生效时间、iat (Issued At):签发时间、jti (JWT ID):编号

除了官方字段还可以定义私有字段

如例:

{
  "sub": "1234567890",
  "name": "John Doe",
  "admin": true
}

  然后和第一部分一样使用Base64Url算法转化一下,由于这部分直接是暴露出去的顾不应该放比较重要的数据。

3.Signature

Signature 部分是对前两部分的签名,防止数据篡改。

首先,需要指定一个密钥(secret)。这个密钥只有服务器才知道,不能泄露给用户。然后,使用 Header 里面指定的签名算法(默认是 HMAC SHA256),按照下面的公式产生签名。

HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
  secret)

算出签名以后,把 Header、Payload、Signature 三个部分拼成一个字符串,每个部分之间用"点"(.)分隔,就可以返回给用户。

关于jwt的介绍就到这里 ,参考了网上的其他人博客和JWT官网想要了解的更加详细可以前去官网仔细阅读一下。

二、构建demo

首先新建一个spring boot 项目 pom文件如下

 <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>com.auth0</groupId>
            <artifactId>java-jwt</artifactId>
            <version>3.7.0</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.58</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

  然后新建一个实体类user 包括了id,name,password和一个EntRespon用于网络之间消息的传输。

public class User {
    private String id;
    private String name;
    private String password;

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}

  

public class EntRespson {
    private int code;
    private String resultMsg;
    private Object data;

    public EntRespson() {
        this.code=0;
    }

    public int getCode() {
        return code;
    }

    public void setCode(int code) {
        this.code = code;
    }

    public String getResultMsg() {
        return resultMsg;
    }

    public void setResultMsg(String resultMsg) {
        this.resultMsg = resultMsg;
    }

    public Object getData() {
        return data;
    }

    public void setData(Object data) {
        this.data = data;
    }
}

   然后新建一个controller 先写一个测试方法 test 先测试没有问题 。然后我们需要完成一个JWT加密解密的方法,以下使我们的一个简单的JWT加密解密的方法。

public class JwtUtils {

    public static final String TOKEN_HEADER = "Authorization";
    public static final String TOKEN_PREFIX = "Bearer ";

    private static final String SECRET = "jwtdemo";
    private static final String ISS = "echisan";

    // 过期时间
    private static final long EXPIRATION = 360000l;

    /**
     * 加密 jwt token
     * @param id
     * @return
     */
    public static String encode(String id) {
        Algorithm algorithm = Algorithm.HMAC256(SECRET);
        String token = JWT.create()
                //设置过期时间为一个小时
                .withExpiresAt(new Date(System.currentTimeMillis() + EXPIRATION))
                //设置负载
                .withJWTId(id)
                .sign(algorithm);
        return token;
    }

    /**
     *  解密 jwt toke
     * @param token
     * @return
     */
    public static String decode(String token) {
        if (token == null || token.length() == 0) {
            throw new RuntimeException("token为空:" + token);
        }
        Algorithm algorithm = Algorithm.HMAC256(SECRET);
        JWTVerifier jwtVerifier = JWT.require(algorithm).build();
        DecodedJWT decodedJWT = jwtVerifier.verify(token);
        return decodedJWT.getId();
    }

}

     由于我们这demo没有连接数据库所以我把用户信息写在配置文件里面了 application.properties 如下

demo.name=lee
demo.password=123
demo.id=1

  然后我们完成一个读取配置文件的类

@Configuration
@PropertySource("classpath:application.properties")
public class UserConfig {
    @Value("${demo.name}")
    private String name;
    @Value("${demo.password}")
    private String password;
    @Value("${demo.id}")
    private String id;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }
}

  

这个时候完成controller 里面的登录方法,在登录完成后 生成一个token返还给前端这个就是一个获取受保护的凭证。

@RestController
public class CtrlUser {
    @Autowired
    private UserConfig config;

    @RequestMapping("test1")
    public String test() {
        return "ok test" + config.getName();
    }

    @RequestMapping(value = "login", method = RequestMethod.POST)
    public EntRespson login(@RequestBody User user) {
        EntRespson entRespson = new EntRespson();
        try {
            String usename = config.getName();
            String pwds = config.getPassword();
            if (!(user.getName().equals(usename) &&
                    user.getPassword().equals(pwds)))throw new Exception("账户密码错误");
            //登录成功获得token
            String token = JwtUtils.encode(config.getId());
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("token",token);
            entRespson.setData(jsonObject);
        } catch (Exception e) {
            entRespson.setCode(-1);
            entRespson.setResultMsg(e.getMessage());
        }
        return entRespson;
    }
}

 现在我们还是完成一个简单的拦截器的功能。

public class Interceptor implements HandlerInterceptor {
    @Autowired
    private UserConfig config;
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String token = request.getHeader("token");// HttpServletRequest 请求头中取出 token
        if (!(handler instanceof HandlerMethod)) {
            return true;
        }

//        HandlerMethod handlerMethod = (HandlerMethod) handler;
//        Method method = handlerMethod.getMethod();
//        //检查是否有passtoken注释,有则跳过认证
//        if (method.isAnnotationPresent(SkipToken.class)) {
//            SkipToken passToken = method.getAnnotation(SkipToken.class);
//            if (passToken.required()) {
//                return true;
//            }
//        }
        String id = JwtUtils.decode(token);
        if (id.equals(config.getId()))
            return true;
        return false;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {

    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {

    }
}

  把拦截器添加到配置类中

@Configuration
public class InterceptorConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(getInterceptor())
                .addPathPatterns("/**")             //配置拦截所有请求
                .excludePathPatterns("/login");    // 不拦截登录请求。
    }

    @Bean
    public Interceptor getInterceptor(){
        return new Interceptor();
    }
}

  好了 到此为止我们的demo已经完成了我们开始测试我们是demo。

启动完成之后我们先试试127.0.0.1:8080/test1

   这里可以看到我们请求被拒绝了 ,然后我们测试一下登录接口。

到这里我们已经获取到了token,前端在获取了token之后前端是逻辑是需要在每一次请求的Headers里面增加一个token,我们在上一个测试接口里面加上token重新请求一下

好的在这里我们已经能看到了我们带有token的请求已经访问成功了。

最后附上源码地址:https://github.com/llcin/spring_tool/tree/master/mydemo

原文地址:https://www.cnblogs.com/Kevinmanlee/p/11296656.html

时间: 2024-11-01 23:15:59

spring boot+jwt 权限验证的相关文章

spring boot shiro -权限管理

spring boot shiro -权限管理 定义 java最常用的框架有spring security 和Apache shiro,因为spring security 庞大和负责,一般使用都是Apache shiro. Apache shiro 是一个功能强大,灵活,开源的安全框架,它可以处理身份验证,授权,企业会话管理,加密等. shiro 易于理解和使用,一个好的框架 应该屏蔽复杂性,向外提供简单,直观的api,简化开发人员实行应用程序安全所发费的时间和精力. shiro 可以做什么:

从壹开始前后端分离[.netCore 不定期 ] 36 ║解决JWT权限验证过期问题

缘起 哈喽,老张的不定期更新的日常又开始了,在咱们的前后端分离的.net core 框架中,虽然已经实现了权限验证<框架之五 || Swagger的使用 3.3 JWT权限验证[修改]>,只不过还是有一些遗留问题,最近有不少的小伙伴发现了这样的一些问题,本来想着直接就在原文修改,但是发现可能怕有的小伙伴看不到,就单发一条推送吧,所以我还是单写出一篇文章来说明解决这些问题,希望对无论是正在开发权限管理系统,还是平时需要数据库动态绑定权限分配的你有一些启发和思考.今天咱们注意解决这三个问题: 1.

Spring Boot Shiro 权限管理 【转】

http://blog.csdn.net/catoop/article/details/50520958 主要用于备忘 本来是打算接着写关于数据库方面,集成MyBatis的,刚好赶上朋友问到Shiro权限管理,就先总结下发出来了. 使用Shiro之前用在spring MVC中,是通过XML文件进行配置. 既然现在在写Spring Boot的帖子,就将Shiro应用到Spring Boot中,我本地已经完成了SpringBoot使用Shiro的实例,将配置方法共享一下. 先简单介绍一下Shiro,

十、 Spring Boot Shiro 权限管理

使用Shiro之前用在spring MVC中,是通过XML文件进行配置. 将Shiro应用到Spring Boot中,本地已经完成了SpringBoot使用Shiro的实例,将配置方法共享一下. 先简单介绍一下Shiro,对于没有用过Shiro的朋友,也算是做个简介吧. Shiro是Apache下的一个开源项目,我们称之为Apache Shiro.它是一个很易用与Java项目的的安全框架,提供了认证.授权.加密.会话管理,与 Spring Security 一样都是做一个权限的安全框架,但是与S

spring boot + jwt + spring security前后端分离实现权限控制

参考链接: https://www.cnblogs.com/jinbuqi/p/11021971.html https://blog.csdn.net/I_am_Hutengfei/article/details/100561564 原文地址:https://www.cnblogs.com/jayinnn/p/12171863.html

Spring Boot SpringSecurity5 身份验证

对于没有访问权限的用户需要转到登录表单页面.要实现访问控制的方法多种多样,可以通过Aop.拦截器实现,也可以通过框架实现(如:Apache Shiro.Spring Security). pom.xml添加依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependen

spring boot + shiro 登录验证

form提交 <form th:action="@{/login}" method="POST"> <div class="form-group has-feedback"> <input name="username" type="text" class="form-control" placeholder="用户账户" require

spring boot 表单验证

1 设置某个字段的取值范围 1.1 取值范围验证:@Min,@Max ① 实例类的属性添加注解@Min ② Controller中传入参数使用@Valid注解 1.2 不能为空验证:@NotNull 对pojo类的属性使用@NotNull注解即可 原文地址:https://www.cnblogs.com/Latiny/p/9003402.html

Spring Boot 整合滑动验证

极验是一种利用生物特征与人工智能技术解决人机交互安全问题的技术,旨在解决安全验证问题,例如:账号登录.短信验证.批量注册等,目前极验.网易易盾比较出众. 在这里主要使用的极验Geetest和springboot 框架整合. 1.首先到极验官网注册账号获取ID和KEY,这里赘述. 2.到极验官网下载,使用SDK,点击下载,如果你使用时Git工具, #git clone https://github.com/GeeTeam/gt3-java-sdk.git 3.引入SDK到Springboot项目中