栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

SpringBoot+SpringSecurity+RBAC+JWT实现动态权限框架

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

SpringBoot+SpringSecurity+RBAC+JWT实现动态权限框架

一、创建数据库表
DROp TABLE IF EXISTS luo_admin;
CREATE TABLE luo_admin (
id bigint(20) NOT NULL AUTO_INCREMENT,
username varchar(64) DEFAULT NULL,
password varchar(64) DEFAULT NULL,
icon varchar(500) DEFAULT NULL COMMENT ‘头像’,
email varchar(100) DEFAULT NULL COMMENT ‘邮箱’,
nick_name varchar(200) DEFAULT NULL COMMENT ‘昵称’,
note varchar(500) DEFAULT NULL COMMENT ‘备注信息’,
create_time datetime DEFAULT NULL COMMENT ‘创建时间’,
login_time datetime DEFAULT NULL COMMENT ‘最后登录时间’,
status int(1) DEFAULT ‘1’ COMMENT ‘帐号启用状态:0->禁用;1->启用’,
PRIMARY KEY (id)
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8 COMMENT=‘后台用户表’;
添加数据:
INSERT INTO luo_admin VALUES (3, ‘admin’, ‘$2a 10 10 10TyteFqX1w78EDX81d4wr6.pJEYm9b9BdjJ1QF/U./ZEz9RuubWOE2’, ‘http://macro-oss.oss-cn-shenzhen.aliyuncs.com/mall/images/20190129/170157_yIl3_1767531.jpg’, ‘admin@163.com’, ‘系统管理员’, ‘系统管理员’, ‘2018-10-08 13:32:47’, ‘2022-06-21 10:35:39’, 1);
INSERT INTO luo_admin VALUES (10, ‘Test’, ‘$2a 10 10 10amtbA4JqnEshTdTKBAYPzumwDu4PMlbnulYPjGncfra2wXs92ao2K’, NULL, ‘testqq.com’, ‘测试账号’, ‘111’, ‘2022-06-21 10:30:21’, ‘2022-06-21 10:32:50’, 1);
DROP TABLE IF EXISTS luo_admin_permission_relation;
CREATE TABLE luo_admin_permission_relation (
id bigint(20) NOT NULL AUTO_INCREMENT,
admin_id bigint(20) DEFAULT NULL,
permission_id bigint(20) DEFAULT NULL,
type int(1) DEFAULT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8 COMMENT=‘后台用户和权限关系表(除角色中定义的权限以外的加减权限)’;
INSERT INTO luo_admin_permission_relation VALUES (1, 3, 16, -1);
INSERT INTO luo_admin_permission_relation VALUES (2, 3, 17, -1);
INSERT INTO luo_admin_permission_relation VALUES (3, 3, 18, -1);
INSERT INTO luo_admin_permission_relation VALUES (4, 3, 19, -1);
INSERT INTO luo_admin_permission_relation VALUES (5, 3, 20, -1);
INSERT INTO luo_admin_permission_relation VALUES (6, 3, 21, -1);
CREATE TABLE luo_admin_role_relation (
id bigint(20) NOT NULL AUTO_INCREMENT,
admin_id bigint(20) DEFAULT NULL,
role_id bigint(20) DEFAULT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB AUTO_INCREMENT=23 DEFAULT CHARSET=utf8 COMMENT=‘后台用户和角色关系表’;
INSERT INTO luo_admin_role_relation VALUES (13, 3, 1);
INSERT INTO luo_admin_role_relation VALUES (21, 3, 5);
INSERT INTO luo_admin_role_relation VALUES (22, 10, 5);
CREATE TABLE luo_permission (
id bigint(20) NOT NULL AUTO_INCREMENT,
pid bigint(20) DEFAULT NULL COMMENT ‘父级权限id’,
name varchar(100) DEFAULT NULL COMMENT ‘名称’,
value varchar(200) DEFAULT NULL COMMENT ‘权限值’,
component varchar(500) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT ‘组件名’,
type int(1) DEFAULT NULL COMMENT ‘权限类型:0->目录;1->菜单;2->按钮(接口绑定权限)’,
uri varchar(200) DEFAULT NULL COMMENT ‘前端资源路径’,
title varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT ‘标题’,
create_time datetime DEFAULT NULL COMMENT ‘创建时间’,
status int(1) DEFAULT NULL COMMENT ‘启用状态;0->禁用;1->启用’,
PRIMARY KEY (id)
) ENGINE=InnoDB AUTO_INCREMENT=22 DEFAULT CHARSET=utf8 COMMENT=‘后台用户权限表’;
INSERT INTO luo_permission VALUES (1, 0, ‘Layout’, ‘pms:medicine:redad’, ‘Layout’, NULL, ‘/’, ‘Layout’, ‘2022-06-15 21:11:28’, 1);
INSERT INTO luo_permission VALUES (2, 1, ‘Home’, ‘pms:medicine:redad’, ‘Home’, NULL, ‘/home’, ‘首页’, ‘2022-06-15 21:11:31’, 1);
INSERT INTO luo_permission VALUES (3, 1, ‘BaseCompany’, ‘pms:medicine:redad’, ‘CompanyManage’, NULL, ‘/base/company’, ‘医药公司管理’, ‘2022-06-15 21:16:08’, 1);
INSERT INTO luo_permission VALUES (4, 1, ‘BaseSale’, ‘pms:medicine:redad’, ‘SaleManage’, NULL, ‘/base/sale’, ‘销售地点管理’, ‘2022-06-15 21:16:11’, 1);
INSERT INTO luo_permission VALUES (5, 1, ‘BaseCity’, ‘pms:medicine:redad’, ‘CityManage’, NULL, ‘/base/city’, ‘城市信息管理’, ‘2022-06-15 21:16:15’, 1);
INSERT INTO luo_permission VALUES (6, 1, ‘ManageDrug’, ‘pms:medicine:redad’, ‘DrugManage’, NULL, ‘/manage/drug’, ‘药品信息管理’, ‘2022-06-15 21:16:18’, 1);
INSERT INTO luo_permission VALUES (7, 1, ‘MedicalPolicy’, ‘pms:medicine:redad’, ‘MedicalPolicy’, NULL, ‘/manage/medical/policy’, ‘医保政策管理’, ‘2022-06-15 21:16:21’, 1);
INSERT INTO luo_permission VALUES (8, 1, ‘CompanyPolicy’, ‘pms:medicine:redad’, ‘CompanyPolicy’, NULL, ‘/manage/company/policy’, ‘医药公司政策管理’, ‘2022-06-15 21:16:24’, 1);
INSERT INTO luo_permission VALUES (9, 1, ‘DoctorManage’, ‘pms:medicine:redad’, ‘DoctorManage’, NULL, ‘/manage/doctor’, ‘医生信息管理’, ‘2022-06-15 21:16:28’, 1);
INSERT INTO luo_permission VALUES (10, 1, ‘MaterialManage’, ‘pms:medicine:redad’, ‘MaterialManage’, NULL, ‘/manage/material’, ‘必备材料管理’, ‘2022-06-15 21:16:32’, 1);
INSERT INTO luo_permission VALUES (12, 1, ‘luo’, ‘pms:medicine:redad’, ‘Layout’, NULL, ‘/admin’, ‘权限’, ‘2022-06-16 11:40:08’, 1);
INSERT INTO luo_permission VALUES (13, 12, ‘admin’, ‘pms:medicine:redad’, ‘admin’, NULL, ‘/luo/admin’, ‘用户列表’, ‘2022-06-16 17:16:44’, 1);
INSERT INTO luo_permission VALUES (14, 12, ‘role’, ‘pms:medicine:redad’, ‘role’, NULL, ‘/luo/role’, ‘角色列表’, ‘2022-06-16 17:18:44’, 1);
INSERT INTO luo_permission VALUES (15, 12, ‘allocMenu’, ‘pms:medicine:redad’, ‘allocMenu’, NULL, ‘/luo/allocMenu’, ‘菜单列表’, ‘2022-06-16 17:20:47’, 1);
INSERT INTO luo_permission VALUES (16, 0, ‘adminList’, ‘pms:medicine:redad’, ‘adminList’, NULL, ‘/api/admin/list’, ‘获取用户列表’, ‘2022-06-19 23:06:25’, 1);
INSERT INTO luo_permission VALUES (17, 0, ‘adminRole’, ‘pms:medicine:redad’, ‘adminRole’, NULL, ‘/api/role/listAll’, ‘获取角色列表’, ‘2022-06-19 23:23:11’, 1);
INSERT INTO luo_permission VALUES (18, 0, ‘adminRoleUpdate’, ‘pms:medicine:add’, ‘adminRoleUpdate’, NULL, ‘/api/admin/role/update’, ‘修改用户角色’, ‘2022-06-20 11:02:53’, 1);
INSERT INTO luo_permission VALUES (19, 0, ‘updateAdmin’, ‘pms:medicine:update’, ‘updateAdmin’, NULL, ‘/api/admin/update/v/’, ‘修改用户数据’, ‘2022-06-20 11:21:51’, 1);
INSERT INTO luo_permission VALUES (20, 0, ‘deleteAdmin’, ‘pms:medicine:delete’, ‘deleteAdmin’, NULL, ‘/api/admin/delete/v/’, ‘删除用户数据’, ‘2022-06-21 09:47:31’, 1);
INSERT INTO luo_permission VALUES (21, 0, ‘addAdmin’, ‘pms:medicine:add’, ‘addAdmin’, NULL, ‘/api/admin/register’, ‘添加用户数据’, ‘2022-06-21 10:13:45’, 1);
DROP TABLE IF EXISTS luo_role;
CREATE TABLE luo_role (
id bigint(20) NOT NULL AUTO_INCREMENT,
name varchar(100) DEFAULT NULL COMMENT ‘名称’,
description varchar(500) DEFAULT NULL COMMENT ‘描述’,
admin_count int(11) DEFAULT NULL COMMENT ‘后台用户数量’,
create_time datetime DEFAULT NULL COMMENT ‘创建时间’,
status int(1) DEFAULT ‘1’ COMMENT ‘启用状态:0->禁用;1->启用’,
sort int(11) DEFAULT ‘0’,
PRIMARY KEY (id)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8 COMMENT=‘后台用户角色表’;
INSERT INTO luo_role VALUES (1, ‘系统管理员’, ‘系统管理员’, 0, ‘2018-09-30 15:46:11’, 1, 0);
INSERT INTO luo_role VALUES (5, ‘医生’, ‘医生’, 0, ‘2022-06-20 10:50:48’, 1, 0);
DROP TABLE IF EXISTS luo_role_permission_relation;
CREATE TABLE luo_role_permission_relation (
id bigint(20) NOT NULL AUTO_INCREMENT,
role_id bigint(20) DEFAULT NULL,
permission_id bigint(20) DEFAULT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB AUTO_INCREMENT=30 DEFAULT CHARSET=utf8 COMMENT=‘后台用户角色和权限关系表’;
INSERT INTO luo_role_permission_relation VALUES (1, 1, 1);
INSERT INTO luo_role_permission_relation VALUES (2, 1, 2);
INSERT INTO luo_role_permission_relation VALUES (3, 1, 3);
INSERT INTO luo_role_permission_relation VALUES (4, 1, 4);
INSERT INTO luo_role_permission_relation VALUES (5, 1, 5);
INSERT INTO luo_role_permission_relation VALUES (6, 1, 6);
INSERT INTO luo_role_permission_relation VALUES (7, 1, 7);
INSERT INTO luo_role_permission_relation VALUES (8, 1, 8);
INSERT INTO luo_role_permission_relation VALUES (18, 1, 9);
INSERT INTO luo_role_permission_relation VALUES (19, 1, 10);
INSERT INTO luo_role_permission_relation VALUES (21, 1, 11);
INSERT INTO luo_role_permission_relation VALUES (22, 1, 12);
INSERT INTO luo_role_permission_relation VALUES (23, 1, 13);
INSERT INTO luo_role_permission_relation VALUES (24, 1, 14);
INSERT INTO luo_role_permission_relation VALUES (25, 1, 15);
INSERT INTO luo_role_permission_relation VALUES (28, 5, 1);
INSERT INTO luo_role_permission_relation VALUES (29, 5, 2);
二、创建SpringSecurity配置类
1.白名单配置

@Component
@ConfigurationProperties(prefix = "secure.ignored")
public class IgnoreUrlsConfig {
    private List urls = new ArrayList<>();

    public List getUrls() {
        return urls;
    }

    public void setUrls(List urls) {
        this.urls = urls;
    }
}
secure:
  ignored:
    urls: #安全路径白名单
      - *.html
      - *.js
      - *.css
      - *.png
      - /favicon.ico
      - /actuator
    public CorsConfigurationSource corsConfigurationSource() {

        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();

        CorsConfiguration configuration = new CorsConfiguration();

        configuration.setAllowCredentials(true);
        configuration.addAllowedHeader("*");
        configuration.setAllowedMethods(Collections.singletonList("*"));
        configuration.setAllowedOriginPatterns(Collections.singletonList("*"));
        configuration.setMaxAge(Duration.ofHours(1));
        source.registerCorsConfiguration("
@Component
public class DynamicAccessDecisionManager implements AccessDecisionManager {
    
    @Override
    public void decide(Authentication authentication, Object object, Collection configAttributes) throws AccessDeniedException, InsufficientAuthenticationException {
        // 当接口未被配置资源时直接放行
        if (CollUtil.isEmpty(configAttributes)){
            return;
        }
        //将访问所需资源和用户拥有资源进行比较
        Iterator iterator = configAttributes.iterator();
        while (iterator.hasNext()){
            ConfigAttribute configAttribute = iterator.next();
            String needAuthority = configAttribute.getAttribute();
            for (GrantedAuthority authority : authentication.getAuthorities()) {
                if (needAuthority.trim().equals(authority.getAuthority())){
                    return;
                }
            }
        }
        throw  new AccessDeniedException("抱歉,您没有访问权限");
    }

    
    @Override
    public boolean supports(ConfigAttribute attribute) {
        return true;
    }

    
    @Override
    public boolean supports(Class clazz) {
        return true;
    }
}


package com.lm.common.utils;

import com.lm.config.IgnoreUrlsConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpMethod;
import org.springframework.security.access.SecurityMetadataSource;
import org.springframework.security.access.intercept.AbstractSecurityInterceptor;
import org.springframework.security.access.intercept.InterceptorStatusToken;
import org.springframework.security.web.FilterInvocation;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.PathMatcher;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.List;


@Component
public class DynamicSecurityFilter  extends AbstractSecurityInterceptor implements Filter {
    @Autowired
    private DynamicSecurityMetadataSource dynamicSecurityMetadataSource;
    @Autowired
    private IgnoreUrlsConfig ignoreUrlsConfig;
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest)servletRequest;
        //FilterInvocation
        FilterInvocation fi = new FilterInvocation(servletRequest,servletResponse,filterChain);
        //如果是options请求就放行,
        //当发起跨域请求时,由于安全原因,触发一定条件时浏览器会在正式请求之前自动先发起 OPTIONS 请求,即 CORS 预检请求,服务器若接受该跨域请求,浏览器才继续发起正式请求。
        if (request.getMethod().equals(HttpMethod.OPTIONS.toString())){
            fi.getChain().doFilter(fi.getRequest(),fi.getResponse());
            return;
        }
        //白名单直接放行
        PathMatcher pathMatcher = new AntPathMatcher();
        List urls = ignoreUrlsConfig.getUrls();
        for (String url : urls) {
            if (pathMatcher.match(url,request.getRequestURI())){
                fi.getChain().doFilter(fi.getRequest(),fi.getResponse());
                return;
            }
        }
        //此处会调用AccessDecisionManager中的decide方法进行鉴权操作
        InterceptorStatusToken token = super.beforeInvocation(fi);
        try {
            fi.getChain().doFilter(fi.getRequest(),fi.getResponse());
        }catch (Exception e){
            super.afterInvocation(token,null);
        }
    }

    @Override
    public Class getSecureObjectClass() {
        return FilterInvocation.class;
    }

    @Override
    public SecurityMetadataSource obtainSecurityMetadataSource() {
        return dynamicSecurityMetadataSource;
    }

    @Autowired
    public void setMyAccessDecisionManager(DynamicAccessDecisionManager dynamicAccessDecisionManager){
        super.setAccessDecisionManager(dynamicAccessDecisionManager);
    }


}
package com.lm.common.utils;


import cn.hutool.core.util.URLUtil;
import com.lm.pojo.UmsAdmin;
import com.lm.pojo.UmsPermission;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.PathMatcher;

import java.util.*;


@Component
public class DynamicSecurityMetadataSource implements FilterInvocationSecurityMetadataSource {
    @Override
    public Collection getAttributes(Object object) throws IllegalArgumentException {

        List configAttributes = new ArrayList<>();
        //获取当前访问路径
        String url = ((FilterInvocation) object).getRequestUrl();
        //http://localhost:8080/search/name=zhangsan&age=20 完事后只保留/search
        //该方法用于获取URL链接中的path部分字符串
        String path = URLUtil.getPath(url);
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        Object principal1 = authentication.getPrincipal();
        UmsAdmin userDetails = null;
        if (principal1 instanceof UserDetails) {
            userDetails = (UmsAdmin) principal1;
            List permissions = userDetails.getPermissions();
            PathMatcher pathMatcher = new AntPathMatcher();
            for (UmsPermission umsPermission : permissions) {
                if (pathMatcher.match(umsPermission.getUri(), path)) {
                    SecurityConfig securityConfig = new SecurityConfig(umsPermission.getId() + ":" + umsPermission.getValue());
                    configAttributes.add(securityConfig);
                }

            }
        }

        if (configAttributes.isEmpty()){
            //没有匹配到资源,返回ROLE_LOGIN
            return SecurityConfig.createList("ROLE_LOGIN");
        }
        //未设置权限返回空集合
        return configAttributes;
    }

    @Override
    public Collection getAllConfigAttributes() {
        return null;
    }

    @Override
    public boolean supports(Class clazz) {
        return true;
    }
}
package com.lm.common.utils;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.authentication.WebAuthenticationDetails;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;


@Slf4j
@Component
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
    @Autowired
    private UserDetailsService userDetailsService;
    @Autowired
    private JwtTokenUtils jwtTokenUtil;
    @Value("${jwt.tokenHeader}")
    private String tokenHeader;
    @Value("${jwt.tokenHead}")
    private String tokenHead;
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        String authHeader = request.getHeader(this.tokenHeader);
        //如果获取的token不为空,并且 头部是相同的就返回true
        if (authHeader != null && authHeader.startsWith(this.tokenHead)) {
            String userToken = authHeader.substring(this.tokenHead.length());
            String userName = jwtTokenUtil.getUserNameFromToken(userToken);
            log.info("checking userName:{}",userName);
            //判断数据库中是否有此用户,并且判断没有其他用户已登录
            if (userName != null && SecurityContextHolder.getContext().getAuthentication() == null){
                UserDetails userDetails = this.userDetailsService.loadUserByUsername(userName);
                //判断当前用户是否过期
                if (jwtTokenUtil.validateToken(userToken,userDetails)){
                    //验证密码
                    //用户名和密码被过滤器获取到,封装成Authentication,通常情况下是UsernamePasswordAuthenticationToken这个实现类
                    UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken =
                            new UsernamePasswordAuthenticationToken(userDetails,null,userDetails.getAuthorities());
                    usernamePasswordAuthenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
                    log.info("checking userName:{}",userName);
                    //如果用户存在且用户的密码相同,则在SecurityContextHolder.getContext().setAuthentication()放入authentication
                    SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);

                }
            }
        }
        filterChain.doFilter(request,response);
    }
}
package com.lm.common.utils;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;


@Component
@Slf4j
public class JwtTokenUtils {
    @Value("${jwt.expiration}")
    private Long expiration;
    @Value("${jwt.secret}")
    private String secret;
    private static final String CLAIM_KEY_USERNAME = "sub";
    private static final String CLAIM_KEY_CREATED = "created";
    
    private String generateToken(Map claims) {
        return Jwts.builder()
                .setClaims(claims)
                .setExpiration(generateExpirationDate())
                .signWith(SignatureAlgorithm.HS512, secret)
                .compact();
    }

    
    private Claims getClaimsFromToken(String token){
        Claims claims = null;
        try {
            claims = Jwts.parser()
                    .setSigningKey(secret)
                    .parseClaimsJws(token)
                    .getBody();
        }catch (Exception e){
            log.info("JWT格式验证失败:{}",token);
        }
        return claims;
    }

    public String getUserNameFromToken(String token){
        String userName;
        try {
            Claims claims = getClaimsFromToken(token);
            userName = claims.getSubject();
        }catch (Exception e){
            userName = null;
        }
        return userName;
    }
    
    public Date generateExpirationDate(){
        return new Date(System.currentTimeMillis()+expiration*1000);
    }

    
    public boolean isTokenExpired(String token){
        Date expiredDateFromToken = getExpiredDateFromToken(token);
        return expiredDateFromToken.before(new Date());
    }

    
    public Date getExpiredDateFromToken(String token){
        Claims claims = getClaimsFromToken(token);
        return claims.getExpiration();
    }

    
    public boolean validateToken(String token, UserDetails userDetails){
        String userName = getUserNameFromToken(token);
        return userName.equals(userDetails.getUsername()) && !isTokenExpired(token);
    }

    
    public String generateToken(UserDetails userDetails){
        Map claims = new HashMap<>();
        claims.put(CLAIM_KEY_USERNAME,userDetails.getUsername());
        claims.put(CLAIM_KEY_CREATED,new Date());
        return generateToken(claims);
    }

    
    public boolean canRefresh(String token){return isTokenExpired(token);}

    
    public String refreshToken(String token){
        Claims claimsFromToken = getClaimsFromToken(token);
        claimsFromToken.put(CLAIM_KEY_CREATED,new Date());
        return generateToken(claimsFromToken);
    }
}
package com.lm.common.utils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.lm.common.api.CommonResult;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.stereotype.Component;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;


@Component
public class RestAuthenticationEntryPoint implements AuthenticationEntryPoint {
    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json");
        CommonResult unauthorized = CommonResult.unauthorized(authException.getMessage());
        response.getWriter().println(JSONObject.toJSONString(unauthorized));
        response.getWriter().flush();
    }
}
package com.lm.common.utils;

import com.alibaba.fastjson.JSONObject;
import com.lm.common.api.CommonResult;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.stereotype.Component;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;


@Component
public class RestfulAccessDeniedHandler implements AccessDeniedHandler{
    @Override
    public void handle(HttpServletRequest request,
                       HttpServletResponse response,
                       AccessDeniedException e) throws IOException, ServletException {
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json");
        response.getWriter().println(JSONObject.toJSONString(CommonResult.forbidden(e.getMessage())));
        response.getWriter().flush();
    }
}

设置跨域

package com.lm.common.filter;

import org.springframework.stereotype.Component;

import javax.servlet.*;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;


@Component
public class CorsFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        response.setHeader("Access-Control-Allow-Origin", "*");
        response.setHeader("Access-Control-Allow-Methods", "POST, GET, PUT, OPTIONS, DELETe, PATCH");
        response.setHeader("Access-Control-Max-Age", "3600");
        response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
        response.setHeader("Access-Control-Expose-Headers", "Location");
        filterChain.doFilter(servletRequest, servletResponse);
    }

    @Override
    public void destroy() {
        Filter.super.destroy();
    }
}

权限实体:

public class UmsAdmin implements Serializable, UserDetails {
    private Long id;

    private String username;

    private String password;

    @ApiModelProperty(value = "头像")
    private String icon;

    @ApiModelProperty(value = "邮箱")
    private String email;

    @ApiModelProperty(value = "昵称")
    private String nickName;

    @ApiModelProperty(value = "备注信息")
    private String note;

    @ApiModelProperty(value = "创建时间")
    private Date createTime;

    @ApiModelProperty(value = "最后登录时间")
    private Date loginTime;

    @ApiModelProperty(value = "帐号启用状态:0->禁用;1->启用")
    private Integer status;

    private static final long serialVersionUID = 1L;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }
    @Override
    public String getUsername() {
        return username;
    }

    private List permissions;

    public List getPermissions() {
        return permissions;
    }

    public void setPermissions(List permissions) {
        this.permissions = permissions;
    }

    提示账号是否过期 true 末过期 false 过期
    @Override
    public boolean isAccountNonExpired() {
        return true;
    }
    是否处于锁定状态
    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    @Override
    //指示用户凭证(密码) 是否过期 true 未过期 false过期
    public boolean isCredentialsNonExpired() {
        return true;
    }

    @Override
    public boolean isEnabled() {
        boolean enabled = true;
        if (this.status == 0){
            enabled = false;
        }
        return enabled;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    @Override
    public Collection getAuthorities() {
        List authorities = new ArrayList<>();
        //返回当前用户的权限
        for (UmsPermission umsPermission : permissions) {
            authorities.add(new SimpleGrantedAuthority(umsPermission.getId() + ":" + umsPermission.getValue()));
        }
        return authorities;
    }
    @Override
    public String getPassword() {
        return password;
    }

mapper 层

@Mapper
public interface AdminMapper {
    public UmsAdmin loadAdminByUserName(String userName);

    public List getUmsRole(Long id);
}


@Mapper
public interface UmsAdminRoleRelationMapper {

    
    List getPermissionList(@Param("adminId") Long adminId);
}

service层

public interface AdminService {
    

    public Map login(String userName,String passWord);

    
    List getPermissionList(Long adminId);


@Service
@Slf4j
public class AdminServiceImpl implements AdminService, UserDetailsService {
    @Autowired
    private AdminMapper adminMapper;
    @Autowired
    private JwtTokenUtils jwtTokenUtil;
    @Autowired
    private PasswordEncoder passwordEncoder;
    @Autowired
    private UmsAdminRoleRelationMapper umsAdminRoleRelationMapper;
    @Autowired
    private UmsRoleMapper umsRoleMapper;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        UmsAdmin umsAdmin = adminMapper.loadAdminByUserName(username);
        if (umsAdmin != null){
            List permissionList = umsAdminRoleRelationMapper.getPermissionList(umsAdmin.getId());
            umsAdmin.setPermissions(permissionList);
            return umsAdmin;
        }
        throw new UsernameNotFoundException("用户名或密码错误");

    }

    @Override
    public Map login(String userName, String passWord) {
        Map loginResult = new HashMap<>();
        String token = null;
        UserDetails userDetails = null;
        try {
             userDetails = loadUserByUsername(userName);
            if(userDetails==null){
                return loginResult;
            }
            if (!passwordEncoder.matches(passWord, userDetails.getPassword())) {
                throw new BadCredentialsException("密码不正确");
            }
            UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
            SecurityContextHolder.getContext().setAuthentication(authentication);
            token = jwtTokenUtil.generateToken(userDetails);
        } catch (AuthenticationException e) {
            log.warn("登录异常:{}", e.getMessage());
        }
        loginResult.put("token",token);
        loginResult.put("userInfo",(UmsAdmin)userDetails);
        return loginResult;
    }

    @Override
    public List getPermissionList(Long adminId) {
        return umsAdminRoleRelationMapper.getPermissionList(adminId);
    }

}

mapper映射



    

控制层:

package com.lm.controller;

import com.lm.common.api.CommonResult;
import com.lm.mapper.UmsAdminRoleRelationMapper;
import com.lm.pojo.UmsPermission;
import com.lm.service.AdminService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.web.bind.annotation.*;


import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


@RestController
public class LoginController {
    @Autowired
    private AdminService adminService;
    @Value("${jwt.tokenHeader}")
    private String tokenHeader;
    @Value("${jwt.tokenHead}")
    private String tokenHead;
    @Autowired
    private UmsAdminRoleRelationMapper umsAdminRoleRelationMapper;


    @RequestMapping(value = "/login",method = RequestMethod.POST)
    public CommonResult login(@RequestParam String username, @RequestParam String password) {
        Map loginResult = adminService.login(username, password);
        if (loginResult.get("token") == null) {
            return CommonResult.validateFailed("用户名或密码错误");
        }
        loginResult.put("tokenHead", tokenHead);
        return CommonResult.success(loginResult);
    }
    @RequestMapping(value = "/permissions",method = RequestMethod.GET)
    public CommonResult permissions(@RequestParam Long  id){
        List permissionList = umsAdminRoleRelationMapper.getPermissionList(id);
        List failPermission = new ArrayList<>();
        for (UmsPermission umsPermission : permissionList) {
           if (umsPermission.getPid() == 0){
               failPermission.add(setChildren(umsPermission, permissionList));
           }
        }

        return CommonResult.success(failPermission);
    }

    public UmsPermission setChildren(UmsPermission father,List permissions){
        List list = new ArrayList<>();
        for (UmsPermission permission : permissions) {
            if (father.getId().equals(permission.getPid())){
                father.setChildren(list);
                father.getChildren().add(setChildren(permission,permissions));
            }
        }
        return father;
    }


}

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1004258.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号