Spring Security与JWT

Spring Security

一. 权限控制

​ 任何一个管理系统都必须要实现权限控制,它是任何一个系统的基础建设部分,以实现对公司不同岗位、不同角色员工的数据隔离。

​ 在早期的权限控制使用的 ACL(Access Control List) 机制,它实现起来简单,对于使用者来说很麻烦,Linux操作系统就是这种机制,因为该操作系统能够使用的人很少。

​ 现代的权限管理使用的是 RBAC(Role Based Access Control),基于角色的访问权限控制。就是给用户授予不同的角色,角色赋予不同的权限。它开发难度变大,但是使用简单。

二. 权限框架

​ 在spring security诞生之前,业界使用的 shiro 这个权限框架,它可以不依赖与web容器和spring的IOC容器。Spring Security是必须要依赖web容器和spring的IOC容器。Spring security它作为 spring的亲儿子,从出生就备受关注,市场份额逐渐替代shiro。

​ Spring Security的学习难度要远远高于 shiro,但是我们按照一个简单的方式来实现权限控制。

三. 权限框架解决的问题

3.1 认证(Authentication)

认证就是解决 “我是谁” 的问题,就是用户是否可以访问该系统。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XsK2ZG8S-1677461821703)(images/authentication.jpg)]

3.2 授权(Authorization)

“授权” 表示用户进入系统只能,“能干什么”。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7U7UfFa1-1677461821704)(images/authorization.jpg)]

四. Springboot整合Security

第一步,导入如下的依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>
4.1 spring security的核心配置
/**
 * 1.@EnableWebSecurity 开启 spring secuirty的自定义配置
 */
@EnableWebSecurity
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    // 关于 认证 和 授权的配置,都在该代码中实现
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        /**
         * 1. authorizeRequests() 方法的目的是为了配置哪些资源需要认证才能访问,哪些资源不需要认证就可以访问;
         * 2. authorizeRequests() 这个方法一旦被调用了,就会覆盖spring security内部的登录表单。
         */
        http.authorizeRequests()  //
//                .antMatchers("/greet").permitAll()  //permitAll() 可以不登录直接访问
                // /user/** 它可以匹配如下的路径: /user  /user/add  /user/add/a/b/c
                // authenticated() 表示对应的资源必须要认证了才能访问
                .antMatchers("/user/**", "/greet").authenticated()   // ant 是spring中的一个路径匹配法则,“*” 表示匹配一个单词,“**” 是递归路径
                .antMatchers("/login").permitAll()
                .and()  // and() 方法表示的意思是,要做另外一个块的配置
                // .formLogin().disable()  // 在前后端分离情况下,需要禁用spring security自带的登录功能
                .csrf().disable(); // csrf() 跨站伪造攻击,禁用掉;如果需要发送非 GET 请求,需要将 crsf() 禁用
    }
}

五. JWT

5.1 前后端分离的Session

下图为标准的session机制

在前后端分离的时候

5.2 JWT

JWT(Json Web Token),他就是一个字符串,它的出现是为了解决前后端分离登录的处理的。它分为3段,每一段之间是通过 “.” 来分割的,前两段其实就是一个 base64 的字符串,说白就是明文。它具有自验证的功能。

5.2.1 JWT的使用

第一步,需要引入如下的依赖

<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-api</artifactId>
    <version>0.11.2</version>
</dependency>
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-impl</artifactId>
    <version>0.11.2</version>
    <scope>runtime</scope>
</dependency>
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-jackson</artifactId> <!-- or jjwt-gson if Gson is preferred -->
    <version>0.11.2</version>
    <scope>runtime</scope>
</dependency>

第二步,jwt的生成

@Test
public void generateJWT() {
    // 密钥,需要绝对保密的一个字符串
    String key = "Qltw8l63IzprU54xLHTK3bzkY40iCLbA26Jo4IZmARXQALz0dBrclPDwkRyOUiDoasOioGtBAPfN0NWmrLC1Og==";
    /**
         * 将用于加密的字符串生成一个 Key 类型的对象
         */
    Key k = new SecretKeySpec(Base64.getDecoder().decode(key), "HmacSHA512");

    // 生成一个 JWT的字符串
    String jwt = Jwts.builder()
        .setSubject("admin")  // 用户名信息,要放到的 payload
        .setIssuedAt(new Date())  // jwt的颁发日期
        .setExpiration(new Date(System.currentTimeMillis() + 2000))   // jwt的有效期
        .signWith(k, SignatureAlgorithm.HS512)  // 生成jwt的算法
        .compact();  // 返回一个 jwt的字符串
    //
    System.out.println(jwt);
}

第三步,jwt的验证

@Test
public void verifyJWT() {
    // 一个jwt的字符串
    String jwt = "eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJhZG1pbiIsImlhdCI6MTY3Njk2Njk1NywiZXhwIjoxNjc2OTY2OTU5fQ.8Ub25SFQbP7K54VcoSD2Y_S9DXg6tXMisKgLuAk0Udcrl7hAZSvhFhIBfWt2I5DfssmH3lhV1wnukiqN2eKfMw";

    // 这是密钥,因为验证 JWT的时候,需要用当时生成的 jwt时候的密钥来进行验证
    String key = "Qltw8l63IzprU54xLHTK3bzkY40iCLbA26Jo4IZmARXQALz0dBrclPDwkRyOUiDoasOioGtBAPfN0NWmrLC1Og==";

    // 将密钥封装成一个 Key类型的对象
    Key k = new SecretKeySpec(Base64.getDecoder().decode(key), "HmacSHA512");

    /**
         * 如下的代码就是用来验证jwt的
         */
    try {
        Claims claims = Jwts.parserBuilder().setSigningKey(k).build().parseClaimsJws(jwt).getBody();
        System.out.println("验证成功");
    }catch (Exception ex) {
        /**
             * 1. 如果抛出的是这个异常:SignatureException,jwt被篡改
             * 2. 如果抛出的是这个异常:MalformedJwtException,jwt被篡改了,格式不对。
             * 3. 如果抛出的是这个异常:ExpiredJwtException,jwt过期,需要重新登录。
             */
        System.out.println(ex.getClass());
    }
}

第四步,jwt加密字符串的生成

@Test
public void generateKey() {
    Key key = Keys.secretKeyFor(SignatureAlgorithm.HS512);
    String k = new String(Base64.getEncoder().encode(key.getEncoded()));
    System.out.println(k);
}

补充

  1. 属性注入,在项目中非架构配置需要单独提取一个 properties 配置文件,例如如下的配置
jwt.jwt-token=Qltw8l63IzprU54xLHTK3bzkY40iCLbA26Jo4IZmARXQALz0dBrclPDwkRyOUiDoasOioGtBAPfN0NWmrLC1Og==
jwt.expire-time=2000000
/**
 * 第一种方式
 * 1.@PropertySource 作用是读取外部 properties 资源的
 * 2.关于配置,application.yml 是框架层面的配置,系统中业务数据不要往 application.yml 中配置
 */
@PropertySource("classpath:app.properties")
@Component   // 只有在容器中才能使用 @Value读取 配置文件中的内容
@Data
public class AppProperties {

    @Value("${jwt.jwt-token}")
    private String jwtToken;

    @Value("${jwt.expire-time}")
    private String expireTime;
}
/**
 * 1.获取配置文件的信息,这个方式用的比较多;
 * 2. @PropertySource 用来指定外部的 properties 配置文件;
 * 3. @ConfigurationProperties 用来指定将哪个前缀下的属性注入到该 Bean的属性中
 */
@PropertySource("classpath:app.properties")
@Component
@ConfigurationProperties(prefix = "jwt")  // prefix: 前缀  sufix: 后缀
@Data
public class AppProperties {

    private String jwtToken;  // 配置文件中有两种写法:jwt-token 或者 jwtToken
    private Long expireTime;  // 配置文件中有两种写法:expire-time 或者 expireTime
}

prefix = “jwt”) // prefix: 前缀 sufix: 后缀
@Data
public class AppProperties {

private String jwtToken;  // 配置文件中有两种写法:jwt-token 或者 jwtToken
private Long expireTime;  // 配置文件中有两种写法:expire-time 或者 expireTime

}


  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
针对你的问题,我可以提供以下的一些思路: 1. 首先,你需要使用Spring Security来实现用户认证和授权。在Spring Security中,你可以配置多个AuthenticationProvider实现不同的认证方式。具体而言,你需要实现一个自定义的AuthenticationProvider,用于验证JWT令牌是否有效。在进行认证时,该AuthenticationProvider会获取到请求头中的JWT令牌,然后进行解析和验证,如果解析和验证成功,就会把该用户的信息构建成一个Authentication对象返回给Spring Security框架。 2. 其次,你需要使用JWT来生成令牌并将其发送给客户端。JWT(Json Web Token)是一种轻量级的身份认证机制,可以在不依赖于Session的情况下实现用户的身份认证和授权。在使用JWT时,你需要创建一个私钥和公钥对,私钥用于对JWT进行签名,公钥用于对JWT进行验证。当用户登录成功后,你需要使用私钥对用户的信息进行签名,生成一个JWT令牌,并将该令牌发送给客户端。客户端在以后的请求中需要将该令牌作为Authorization请求头的值发送给服务端。 3. 最后,你需要在服务端验证JWT令牌的有效性。在服务端接收到请求后,你需要从请求头中获取JWT令牌,并使用公钥对该令牌进行验证,验证成功后就可以获得该用户的信息。在接下来的业务逻辑中,你可以使用该用户的信息来进行权限判断等操作。 希望以上的思路对你有所帮助。如果你需要更加详细的实现步骤,可以参考Spring SecurityJWT相关的官方文档。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值