本站消息

站长简介/公众号

  出租广告位,需要合作请联系站长


+关注
已关注

分类  

暂无分类

标签  

暂无标签

日期归档  

2024-11(1)

spring security配合jjwt完成权限管理01

发布于2021-05-29 21:24     阅读(455)     评论(0)     点赞(5)     收藏(3)


项目需要需要使用jwt token来完成用户状态管理以及使用spring security完成用户权限管理,所以需要将二者配合使用

基础思路:
1:spring security关闭自带的session管理,不需要服务器错处用户信息
2:登录时调用security的用户认证模块
3:security认证成功后通过jwt生成token返回给客户,并且在token中存储其他信息(例如权限信息,也可以存储在redis中)
4:用户操作时通过jwt确认用户是否登录状态(token验证)、获取token携带的权限信息通过security管理权限判断是否有权限做某些事情

第一步:完成sql

CREATE TABLE `user` (
                        `user_id` int(11) NOT NULL AUTO_INCREMENT,
                        `user_name` varchar(20) NOT NULL,
                        `user_pwd` varchar(60) DEFAULT NULL,
                        `enabled` TINYINT(1) DEFAULT '1',
                        PRIMARY KEY (`user_id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8

CREATE TABLE `sys_role` (
                            `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
                            `name` varchar(200) NOT NULL,
                            `description` varchar(200) DEFAULT NULL,
                            PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4

CREATE TABLE `sys_role_user` (
                                 `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
                                 `user_id` bigint(20) unsigned NOT NULL,
                                 `sys_role_id` bigint(20) unsigned NOT NULL,
                                 PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4

CREATE TABLE `sys_permission` (
                                  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
                                  `name` varchar(200) NOT NULL,
                                  `description` varchar(200) DEFAULT NULL,
                                  `url` varchar(200) NOT NULL,
                                  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4



CREATE TABLE `sys_permission_role` (
                                       `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
                                       `role_id` bigint(20) unsigned NOT NULL,
                                       `permission_id` bigint(20) unsigned NOT NULL,
                                       PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4

三张表分别为用户、角色、权限表用于基础的操作

第二步:完成spring security的基础配置

(这里看个人习惯)
1:编写User类

@Entity
@Data
@ToString
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;
    private String username;
    private String password;
    private boolean enabled;
}

2:编写MyUserDetail类用户security中用户

package com.mysecurity.liuyf.pojo;

import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

import java.util.Collection;

public class MyUserDetails implements UserDetails {
    private User user;
    private Collection<GrantedAuthority> roles;
    public MyUserDetails(User user, Collection<GrantedAuthority> roles) {
        this.user = user;
        this.roles = roles;
    }

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return roles;
    }

    @Override
    public String getPassword() {
        return user.getPassword();
    }

    @Override
    public String getUsername() {
        return user.getUsername();
    }

    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }

    @Override
    public boolean isEnabled() {
        return true;
    }
}

这里isAccountNonExpired(判断用户是否被锁定)等我没有用到,所以直接写死了,可根据自己的项目动态改变值

3:编写UserDetailService用于处理用户登录

public class UserDetailService implements UserDetailsService {
    @Autowired
    private UserService userService;
    @Override
    public UserDetails loadUserByUsername(String name) throws UsernameNotFoundException {
        User u=userService.findUserByName(name);
        if (u==null){
            return null;
        }
        MyUserDetails MyUserDetails=new MyUserDetails(u,getGrantedAuthority(u));
        return MyUserDetails;
    }
    public List<GrantedAuthority> getGrantedAuthority(User user){
        List<GrantedAuthority> list = new ArrayList<>();
        List<String> roles=userService.findUserRoleByUserId(user.getId());
            for (String role : roles) {
                list.add(new SimpleGrantedAuthority("ROLE_" + role));
            }
        //加载权限表的东西进来 null
        List<String> permission=userService.findUserPermissionByUserId(user.getId());
            for (String per : permission) {
                list.add(new SimpleGrantedAuthority(per));
            }
        return list;
    }
}

这里就是普通的使用loadUserByUsername加用用户,通过security的认证管理器完成认证用于登录

这样security需要准备的基础就完成了(就是登录位置的准备),下边开始准备jwt的东西
1:准备jwt的工具类:

package com.mysecurity.liuyf.util.jwt;

import io.jsonwebtoken.*;
import lombok.Data;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;

import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.DatatypeConverter;
import java.security.Key;
import java.util.*;

@Component
@Data
public class JwtUtil {
   
    // 密钥
    private String secret="自己编一点随机的字符串";
    //超时时间 用于相加过期时间  s为单位   1(单位:s)=5184000
    private long expire=3600;//3600
    private String header="token";
    // 签发者
    private String issuer="自己的公司名字";


    /*
     * 生成 Token
     */
    public String generateToken (String subject){
        //Create the Signature SecretKey
        final SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
        final byte[] apiKeySecretBytes = DatatypeConverter.parseBase64Binary(Base64.getEncoder().encodeToString(getSecret().getBytes()));
        final Key signingKey = new SecretKeySpec(apiKeySecretBytes, signatureAlgorithm.getJcaName());

        Map<String,Object> headerMap=new HashMap<String,Object>();
        headerMap.put("alg", "HS256");
        headerMap.put("typ", "JWT");
        Date nowDate = new Date();
        //过期时间
        Date expireDate = new Date(nowDate.getTime() + expire * 1000);
        return Jwts.builder()
                .setHeaderParams(headerMap)
                .setSubject(subject)
                .setIssuedAt(nowDate)
                //设置token过期时间
                .setExpiration(expireDate)
                .signWith(SignatureAlgorithm.HS256, signingKey)
                //设置签发人信息
                .setIssuer(getIssuer())
                //设置签发时间
                 .setIssuedAt(nowDate)
                 .compact();
    }
    /**
     * 解析token
     *
     * @param token token
     * @return
     */
    public Claims parseToken(String token) {
        final byte[] apiKeySecretBytes = DatatypeConverter.parseBase64Binary(Base64.getEncoder().encodeToString(getSecret().getBytes()));
        Claims claims =claims = Jwts.parser().setSigningKey(apiKeySecretBytes).parseClaimsJws(token).getBody();
        return claims;
    }
    /**
     * 从令牌中获取用户名
     * @param token
     * @return
     */
    public String getUsernameFromToken(String token) {
        String username;
        try {
            Claims claims = parseToken(token);
            username = claims.getSubject();
        } catch (Exception e) {
            username = null;
        }
        return username;
    }

    /**
     * 判断令牌是否过期
     * @param token
     * @return
     */
    public Boolean isTokenExpired(String token) {
        try {
            Claims claims = parseToken(token);
            Date expiration = claims.getExpiration();
            return expiration.before(new Date());
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * 刷新令牌
     * @param token
     * @return
     */
    public String refreshToken(String token) {
        String refreshedToken;
        try {
            Claims claims = parseToken(token);
            claims.put("created", new Date());
            refreshedToken = generateToken(claims.getSubject());
        } catch (Exception e) {
            refreshedToken = null;
        }
        return refreshedToken;
    }
    /**
     * 验证令牌
     * @param token
     * @param userDetails
     * @return
     */
    public Boolean validateToken(String token, UserDetails userDetails) {
        String username = getUsernameFromToken(token);
        return (username.equals(userDetails.getUsername()) && !isTokenExpired(token));
    }



}

secret:自己随便编一段字符串:类似于"aHR0cHM6Ly9teSaaaaaaaaLm5ldCbbbbbbE4Njg"主要做随机加密的
issuer:签发者,写自己的名字或者公司的名字就好了
这样工具类就写好了,用于token得产生以及验证等操作
下一篇开始做最终代码

原文链接:https://blog.csdn.net/liuyuncd/article/details/117320536



所属网站分类: 技术文章 > 博客

作者:我睡觉爱打呼噜

链接:http://www.javaheidong.com/blog/article/207327/65fb61b7a13d8185c4b6/

来源:java黑洞网

任何形式的转载都请注明出处,如有侵权 一经发现 必将追究其法律责任

5 0
收藏该文
已收藏

评论内容:(最多支持255个字符)