spirng boot spring security jwt 动态配置url权限

项目需求,需要管理员动态配置相关url的权限,网上找的大多不太理想,自己参照某些实现:

当权限变更时,需要实时刷新权限

 

技术栈:

## springboot 2.0 集成 jpa

### 环境:

* 开发工具:Intellij IDEA 2017.1.3
* springboot: **2.0.1.RELEASE**
* jdk:1.8.0_40
* maven:3.3.9
* alibaba Druid 数据库连接池:1.1.9

JWT配置:

jwt:
#  secret: mySecret
#  #token有效期一天
  expiration: 86400
  # 加密秘钥
  secret: f4e2e52034348f86b67cde581c0f9eb5[jwuwb]
  # token有效时长,1天,单位秒
  expire: 86400
  header: token

 



import com.jwuwb.oa.entity.SysUser;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;

import java.util.Date;

/**
 * jwt工具类
 * @author zf
 */
@ConfigurationProperties(prefix = "jwt")
@Component
public class JwtUtil {
    private Logger logger = LoggerFactory.getLogger(getClass());

    private String secret;
    private long expire;
    private String header;

    /**
     * 生成jwt token
     */
    public String generateToken(String userName) {
        Date nowDate = new Date();
        //过期时间
        Date expireDate = new Date(nowDate.getTime() + expire * 1000);

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

    public Claims getClaimByToken(String token) {
        try {
            return Jwts.parser()
                    .setSigningKey(secret)
                    .parseClaimsJws(token)
                    .getBody();
        }catch (Exception e){
            logger.debug("validate is token error ", e);
            return null;
        }
    }

    /**
     * token是否过期
     * @return  true:过期
     */
    public boolean isTokenExpired(Date expiration) {
        return expiration.before(new Date());
    }

    public Boolean validateToken(String token, UserDetails userDetails) {
        SysUser user = (SysUser) userDetails;
        final String username = getClaimByToken(token).getSubject();
        return (username.equals(user.getUsername())
                && !isTokenExpired(token)
        );
    }

    private Boolean isTokenExpired(String token) {
        final Date expiration = getClaimByToken(token).getExpiration();
        return expiration.before(new Date());
    }

    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;
    }
}

 

前置过滤:



import com.google.common.collect.Maps;
import com.jwuwb.oa.model.PermissionMap;
import com.jwuwb.oa.model.PermissionVo;
import com.jwuwb.oa.service.PermissionService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 判断是否具有权限访问当前资源
 * @author zf
 */
@Component("perauthorityservice")
public class PerAuthorityService {

    @Autowired
    private PermissionService permissionService;

    /**
     * 判断是否有权限
     *
     * @param request
     * @param authentication
     * @return
     */
    public boolean hasPermission(HttpServletRequest request, Authentication authentication) {
        Collection<ConfigAttribute> collection = getAttributes(request);
        if (authentication.getPrincipal().equals("anonymousUser")) {
            return false;
        }

        if (null == collection || collection.size() <= 0) {
            return true;
        }

        ConfigAttribute configAttribute;
        String needRole;
        for (Iterator<ConfigAttribute> iterator = collection.iterator(); iterator.hasNext(); ) {
            configAttribute = iterator.next();
            needRole = configAttribute.getAttribute();
            for (GrantedAuthority grantedAuthority : authentication.getAuthorities()) {
                String authority = grantedAuthority.getAuthority();
                if (authority.contains(needRole.trim())) {
                    return true;
                }
            }
        }
        throw new AccessDeniedException("权限不足");
    }

    /**
     * 判定用户请求的url是否在权限表中,如果在权限表中,则返回decide方法,
     * 用来判定用户是否有权限,如果不在权限表中则放行
     *
     * @param request
     * @return
     * @throws IllegalArgumentException
     */
    public Collection<ConfigAttribute> getAttributes(HttpServletRequest request) throws IllegalArgumentException {
        HashMap<String, Collection<ConfigAttribute>> map = PermissionMap.map;
        if (map == null) {
            map = loadResourceDefine();
        }
        for (Map.Entry<String, Collection<ConfigAttribute>> entry : map.entrySet()) {
            String url = entry.getKey();
            if (new AntPathRequestMatcher(url).matches(request)) {
                return map.get(url);
            }
        }
        return null;
    }

    /**
     * 加载权限表中所有权限
     */
    private HashMap<String, Collection<ConfigAttribute>> loadResourceDefine() {
        HashMap<String, Collection<ConfigAttribute>> map = Maps.newHashMap();
        List<PermissionVo> all = permissionService.listAllVo();
        for (PermissionVo vo : all) {
            List<ConfigAttribute> configAttributeList = vo.getRoleNames().stream().map(roleName -> {
                ConfigAttribute configAttribute = new SecurityConfig("ROLE_" + roleName.toUpperCase());
                return configAttribute;
            }).collect(Collectors.toList());
            map.put(vo.getUrl(), configAttributeList);
        }
        PermissionMap.map = map;
        return map;
    }
}

覆写登录后回调:



import com.google.common.collect.Lists;
import com.jwuwb.oa.base.util.StringUtil;
import com.jwuwb.oa.dao.SysUserDao;
import com.jwuwb.oa.entity.Permission;
import com.jwuwb.oa.entity.SysRole;
import com.jwuwb.oa.entity.SysUser;
import com.jwuwb.oa.service.PermissionService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

/**
 * 覆写登录存储权限
 * @author zf
 * @date 2019/12/7
 */
@Service
public class UrlUserService implements UserDetailsService {
    @Autowired
    SysUserDao userDao;
    @Autowired
    PermissionService permissionService;

    @Override
    public UserDetails loadUserByUsername(String userName) {
        //重写loadUserByUsername 方法获得 userdetails 类型用户
        SysUser user = userDao.findByUsername(userName);
        if (user != null) {
            Set<SysRole> roleList = user.getRoleList();
            List<String> list = Lists.newArrayList();
            for (SysRole role : roleList) {
                list.add("ROLE_" + role.getName());
            }
            String roles = StringUtil.transListToString(list);
//            Integer userId = user.getId();
//            //拉取权限和角色信息
//            List<Permission> permissions = permissionService.listByUserId(userId);
            List<GrantedAuthority> grantedAuthorities = new ArrayList<>();
            GrantedAuthority grantedAuthority = new UrlGrantedAuthority(roles);
            grantedAuthorities.add(grantedAuthority);
//            if (permissions != null){
//
//                for (Permission permission : permissions) {
//                    if (permission != null && permission.getName()!=null) {
//                        //填充角色和权限
//                        GrantedAuthority grantedAuthority = new UrlGrantedAuthority(permission.getUrl(),
//                                permission.getMethod());
//                        grantedAuthorities.add(grantedAuthority);
//                    }
//                }
//            }
            user.setGrantedAuthorities(grantedAuthorities);
            return user;
        } else {
            throw new UsernameNotFoundException("admin: " + userName + " do not exist!");
        }
    }
}

涉及到的实体类:



import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.jwuwb.oa.base.util.StringUtil;
import com.jwuwb.oa.entity.SysRole;
import org.springframework.security.core.GrantedAuthority;

import java.util.HashSet;
import java.util.List;
import java.util.Map;

/**
 *
 * @author zf
 * @date 2019/12/7
 */
public class UrlGrantedAuthority implements GrantedAuthority {

    private String roles;

    public String getRoles() {
        return roles;
    }

    public void setRoles(String roles) {
        this.roles = roles;
    }

    private String permissionUrl;
    private String method;


    public String getPermissionUrl() {
        return permissionUrl;
    }

    public void setPermissionUrl(String permissionUrl) {
        this.permissionUrl = permissionUrl;
    }

    public String getMethod() {
        return method;
    }

    public void setMethod(String method) {
        this.method = method;
    }

    public UrlGrantedAuthority (String permissionUrl, String method) {
        this.permissionUrl = permissionUrl;
        this.method = method;
    }
    public UrlGrantedAuthority (String roles) {
        this.roles = roles;
    }

    @Override
    public String getAuthority() {
        return this.roles;
    }
//    @Override
//    public String getAuthority() {
//        return this.permissionUrl + ";" + this.method;
//    }
}

 

用户对象:


import com.fasterxml.jackson.annotation.JsonIgnore;
import com.jwuwb.oa.base.comm.BaseEntity;
import com.jwuwb.oa.base.comm.BeanCopyUtil;
import io.swagger.annotations.ApiParam;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import org.hibernate.annotations.DynamicInsert;
import org.hibernate.annotations.DynamicUpdate;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

import javax.persistence.*;
import java.util.Collection;
import java.util.List;
import java.util.Set;

/**
 * @program: oa
 * @description: 角色
 * @author: zf
 * @create: 2019-12-04 15:25
 **/
@EqualsAndHashCode(callSuper = true)
@Data
@Entity
@Table(name = "jw_user")
@Accessors(chain = true)
@DynamicInsert
@DynamicUpdate
public class SysUser extends BaseEntity implements UserDetails {

    @ApiParam(value = "用户名称")
    private String username;

    @ApiParam(value = "密码")
    @JsonIgnore
    private String password;

    @ManyToMany(cascade = CascadeType.DETACH, fetch = FetchType.EAGER)
    @JoinTable(
            name = "user_role",
            joinColumns = {@JoinColumn(name = "uid", referencedColumnName = "id")},
            inverseJoinColumns = {@JoinColumn(name = "rid", referencedColumnName = "id")})
    private Set<SysRole> roleList;

    @ApiParam(value = "关联部门", example = "10")
    private Integer deptId;

    @ApiParam(value = "职务")
    private String post;

    @ApiParam(value = "昵称")
    private String nickname;

    @ApiParam(value = "部门名称", hidden = true)
    private String deptName;

    @ApiParam(value = "是否是超管用户", hidden = true)
    private Boolean isSuper;

    @ApiParam(value = "是否启用", hidden = true)
    private Boolean enabled;

    @Transient
    @ApiParam(hidden = true)
    @JsonIgnore
    private String roleCode;

    @Transient
    @ApiParam(hidden = true)
    private List<? extends GrantedAuthority> authorities;

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

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

    @JsonIgnore
    public void setGrantedAuthorities(List<? extends GrantedAuthority> authorities) {
        this.authorities = authorities;
    }

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

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

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


    public void copy(SysUser et) {
        BeanCopyUtil.beanCopyWithIngore(et, this);
    }
}

角色对象:



import com.jwuwb.oa.base.comm.BaseEntity;
import com.jwuwb.oa.base.comm.BeanCopyUtil;
import io.swagger.annotations.ApiParam;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import org.hibernate.annotations.DynamicInsert;
import org.hibernate.annotations.DynamicUpdate;

import javax.persistence.*;
import java.util.Set;

/**
 * @program: oa
 * @description: 角色
 * @author: zf
 * @create: 2019-12-04 15:25
 **/
@EqualsAndHashCode(callSuper = true)
@Data
@Entity
@Table(name = "jw_role")
@Accessors(chain = true)
@DynamicInsert
@DynamicUpdate
public class SysRole extends BaseEntity {
    @ApiParam(value = "角色名称")
    private String name;

    @ManyToMany(cascade = CascadeType.DETACH, fetch = FetchType.EAGER)
    @JoinTable(
            name = "role_permission",
            joinColumns = {@JoinColumn(name = "rid", referencedColumnName = "id")},
            inverseJoinColumns = {@JoinColumn(name = "pid", referencedColumnName = "id")})
    private Set<Permission> permissions;

    @ApiParam(value = "角色代码")
    private String roleCode;

    public void copy(SysRole et) {
        BeanCopyUtil.beanCopyWithIngore(et, this);
    }
}

权限资源:



import com.jwuwb.oa.base.comm.BaseEntity;
import com.jwuwb.oa.base.comm.BeanCopyUtil;
import io.swagger.annotations.ApiParam;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import org.hibernate.annotations.DynamicInsert;
import org.hibernate.annotations.DynamicUpdate;

import javax.persistence.Entity;
import javax.persistence.Table;

/**
 * @program: oa
 * @description: 权限
 * @author: zf
 * @create: 2019-12-04 15:25
 **/
@EqualsAndHashCode(callSuper = true)
@Data
@Entity
@Table(name = "jw_permission")
@Accessors(chain = true)
@DynamicInsert
@DynamicUpdate
public class Permission extends BaseEntity {

    @ApiParam(value = "权限名称")
    private String name;

    @ApiParam(value = "权限描述")
    private String descritpion;

    @ApiParam(value = "授权链接")
    private String url;

    @ApiParam(value = "父节点id")
    private int pid;

    @ApiParam(value = "请求方法")
    private String method;

    public void copy(Permission et) {
        BeanCopyUtil.beanCopyWithIngore(et, this);
    }
}

权限资源url 设置规则:/xx/** 或者/xx/xx

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值