热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

springboot整合jwt+springsecurity实现接口动态权限控制

基于springboot+security+jwt,实现接口动态权限控制。关于securityjwt数据库结构准备需要基础表:_user、_role、_user_role、_per

基于springboot + security + jwt,实现接口动态权限控制。关于security jwt



数据库结构准备

需要基础表:_user、_role、_user_role、_permission、_role_permission,其中,用户表结构可以不用这么多,但是角色、权限表那些就需要保持一样,才能够跟配置类对应上。

/*
Navicat Premium Data Transfer
Source Server : localhost
Source Server Type : MySQL
Source Server Version : 50650
Source Host : localhost:3306
Source Schema : hlsd100
Target Server Type : MySQL
Target Server Version : 50650
File Encoding : 65001
Date: 19/11/2021 15:07:47
*/
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for _permission
-- ----------------------------
DROP TABLE IF EXISTS `_permission`;
CREATE TABLE `_permission` (
`permission_id` int(11) NOT NULL AUTO_INCREMENT,
`permission_title` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL,
`url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL,
`pid` int(11) NOT NULL DEFAULT -1 COMMENT '默认-1,-1代表匿名url,其他代表需要权限。',
PRIMARY KEY (`permission_id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 14 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_bin ROW_FORMAT = Compact;
-- ----------------------------
-- Records of _permission
-- ----------------------------
INSERT INTO `_permission` VALUES (1, '获取用户数组', '/user/**', -1);
INSERT INTO `_permission` VALUES (2, '匿名可访问url', '/swagger-ui.html', -1);
INSERT INTO `_permission` VALUES (3, '匿名可访问url', '/swagger-resources/*', -1);
INSERT INTO `_permission` VALUES (4, '匿名可访问url', '/webjars/*', -1);
INSERT INTO `_permission` VALUES (5, '匿名可访问url', '/*/api-docs', -1);
INSERT INTO `_permission` VALUES (6, '匿名可访问url', '/static/**', -1);
INSERT INTO `_permission` VALUES (7, '匿名可访问url', '/api/auth/**', -1);
INSERT INTO `_permission` VALUES (8, '匿名可访问url', '/error/**', -1);
INSERT INTO `_permission` VALUES (9, '匿名可访问url', '/webSocket/**', -1);
INSERT INTO `_permission` VALUES (10, '匿名可访问url', '/favicon.ico', -1);
INSERT INTO `_permission` VALUES (11, '匿名可访问url', '/auth/**', -1);
-- ----------------------------
-- Table structure for _role
-- ----------------------------
DROP TABLE IF EXISTS `_role`;
CREATE TABLE `_role` (
`role_id` int(11) NOT NULL AUTO_INCREMENT,
`role_title` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL,
PRIMARY KEY (`role_id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_bin ROW_FORMAT = Compact;
-- ----------------------------
-- Records of _role
-- ----------------------------
INSERT INTO `_role` VALUES (1, 'admin');
INSERT INTO `_role` VALUES (2, 'root');
INSERT INTO `_role` VALUES (3, 'user');
-- ----------------------------
-- Table structure for _role_permission
-- ----------------------------
DROP TABLE IF EXISTS `_role_permission`;
CREATE TABLE `_role_permission` (
`role_permission_id` int(11) NOT NULL AUTO_INCREMENT,
`role_id` int(11) NULL DEFAULT NULL,
`permission_id` int(11) NULL DEFAULT NULL,
PRIMARY KEY (`role_permission_id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_bin ROW_FORMAT = Compact;
-- ----------------------------
-- Records of _role_permission
-- ----------------------------
INSERT INTO `_role_permission` VALUES (1, 1, 1);
INSERT INTO `_role_permission` VALUES (2, 2, 1);
-- ----------------------------
-- Table structure for _user
-- ----------------------------
DROP TABLE IF EXISTS `_user`;
CREATE TABLE `_user` (
`user_id` int(11) NOT NULL AUTO_INCREMENT,
`user_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL,
`user_gender` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL,
`user_tel` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL,
`user_email` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL,
`user_logo` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL,
`u_acco` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '用户名',
`u_pass` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '密码',
`user_upper_a` int(11) NOT NULL DEFAULT 0 COMMENT '上级a,这里指的是代理商。-1代表没绑定,否则表示是代理商的用户id',
`user_balance` int(11) NOT NULL DEFAULT 0 COMMENT '余额,如果提现了需要减去,这个字段普通用户跟代理商都会有,分销的时候是加到这个字段,',
`user_total_balance` int(11) NOT NULL DEFAULT 0 COMMENT ' 总余额,不管有没有提现,都不会减少。-代理商收入跟分销收入都会加到这里',
`user_upper_b` int(11) NOT NULL DEFAULT 0 COMMENT '上级b,这里指的是代理商。-1代表没绑定,否则表示是代理商的用户id',
`createtime` bigint(13) NULL DEFAULT NULL,
`user_sale_amount` int(11) NOT NULL DEFAULT 0 COMMENT ' 销售额度,代理商才会有,普通用户可以不用考虑该字段,代理商收入会添加到这个字段',
`user_code` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT ' 二维码',
`user_visit` int(11) NOT NULL DEFAULT 0,
`user_version_total` int(11) NOT NULL DEFAULT 0 COMMENT ' ',
`is_agent` int(11) NOT NULL DEFAULT 0,
`last_login_time` bigint(13) NULL DEFAULT NULL,
`user_wx_no` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL,
`invite_code` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL,
PRIMARY KEY (`user_id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 517 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_bin ROW_FORMAT = Compact;
-- ----------------------------
-- Records of _user
-- ----------------------------
INSERT INTO `_user` VALUES (1, 'admin', NULL, NULL, NULL, NULL, 'admin', 'admin', 0, 0, 0, 0, NULL, 0, NULL, 19, 10, 1, NULL, NULL, NULL);
INSERT INTO `_user` VALUES (516, 'ean', '男', '4008823823', '984960659@qq.com', NULL, 'ean', '123456', 0, 0, 0, 0, NULL, 0, NULL, 0, 0, 0, NULL, NULL, NULL);
-- ----------------------------
-- Table structure for _user_role
-- ----------------------------
DROP TABLE IF EXISTS `_user_role`;
CREATE TABLE `_user_role` (
`user_role_id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) NULL DEFAULT NULL,
`role_id` int(11) NULL DEFAULT NULL,
`user_title` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL,
`user_avatar` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL,
`role_title` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL,
`status` int(1) NOT NULL DEFAULT 1,
PRIMARY KEY (`user_role_id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_bin ROW_FORMAT = Compact;
SET FOREIGN_KEY_CHECKS = 1;

jwt相关的工具类


JwtTokenUtils

@Slf4j
@Component
public class JwtTokenUtils implements InitializingBean {
private final JwtSecurityProperties jwtSecurityProperties;
private static final String AUTHORITIES_KEY = "auth";
private Key key;
@Value(("${jwt.base64-secret}"))
private String base64Secret;
public JwtTokenUtils(JwtSecurityProperties jwtSecurityProperties) {
this.jwtSecurityProperties = jwtSecurityProperties;
}
@Override
public void afterPropertiesSet() {
byte[] keyBytes = Decoders.BASE64.decode(base64Secret);
this.key = Keys.hmacShaKeyFor(keyBytes);
}
/*登陆的时候调用这个函数生成token,并记录用户信息以及角色,这个claims参数必须要有roles*/
public String createToken(Map claims) {
String roles = String.valueOf(claims.get("roles"));
String ip = String.valueOf(claims.get("ip"));
if (null == roles || "".equals(roles)) {
roles = "user";
}
Date date = new Date();
return Jwts.builder()
.claim(AUTHORITIES_KEY, claims)
.claim("ROLE", roles)
.claim("IP", ip)
.setId(UUID.randomUUID().toString())
.setIssuedAt(date)
.setExpiration(new Date(date.getTime() + jwtSecurityProperties.getTokenValidityInSeconds()))
.compressWith(CompressionCodecs.DEFLATE)
.signWith(key, SignatureAlgorithm.HS512)
.compact();
}
public Date getExpirationDateFromToken(String token) {
Date expiration;
try {
final Claims claims = getClaimsFromToken(token);
expiration = claims.getExpiration();
} catch (Exception e) {
expiration = null;
}
return expiration;
}
/**
* @Author Ean
* @Description 解析token,返回token的角色数组
* @Date 2021/11/18
*/
public Authentication getAuthentication(String token, HttpServletRequest httpServletRequest) {
if ("Yz78r4DSn3yZrSgT".equals(token)) {//处理携带特殊token的情况
return new UsernamePasswordAuthenticationToken("", token, null);
}
Claims claims = Jwts.parser()
.setSigningKey(key)
.parseClaimsJws(token)
.getBody();
String ip = String.valueOf(claims.get("IP"));
try {
String remoteIp = IpUtils.getIpAddr(httpServletRequest);
if (!remoteIp.equals(ip)) {
log.error("本次请求IP跟token所携带的IP不一致");
throw new Exception("本次请求IP跟token所携带的IP不一致");
}
} catch (Exception e) {
e.printStackTrace();
return null;
}
// log.info("ROLE->" + claims.get("ROLE"));
Collection authorities =
Arrays.stream(claims.get("ROLE").toString().split(","))
.map(SimpleGrantedAuthority::new)
.collect(Collectors.toList());
HashMap map = (HashMap) claims.get("auth");
User principal = new User(map.get("username").toString(), map.get("password").toString(), authorities);
return new UsernamePasswordAuthenticationToken(principal, token, authorities);
}
/*校验token格式是否正确*/
public boolean validateToken(String authToken, HttpServletRequest httpServletRequest) {
try {
Claims claims = Jwts.parser()
.setSigningKey(key)
.parseClaimsJws(authToken)
.getBody();
String ip = String.valueOf(claims.get("IP"));
try {
String remoteIp = IpUtils.getIpAddr(httpServletRequest);
if (!remoteIp.equals(ip)) {
log.error("本次请求IP跟token所携带的IP不一致");
throw new Exception("本次请求IP跟token所携带的IP不一致");
}
} catch (Exception e) {
e.printStackTrace();
return false;
}
return true;
} catch (io.jsonwebtoken.security.SecurityException | MalformedJwtException e) {
log.error("Invalid JWT signature.");
// e.printStackTrace();
} catch (ExpiredJwtException e) {
log.error("Expired JWT token.");
// e.printStackTrace();
} catch (UnsupportedJwtException e) {
log.error("Unsupported JWT token.");
// e.printStackTrace();
} catch (IllegalArgumentException e) {
log.error("JWT token compact of handler are invalid.");
// e.printStackTrace();
}
return false;
}
private Claims getClaimsFromToken(String token) {
Claims claims;
try {
claims = Jwts.parser()
.setSigningKey(key)
.parseClaimsJws(token)
.getBody();
} catch (Exception e) {
claims = null;
}
return claims;
}

IpUtils ip获取工具类

public class IpUtils {
public static String getIpAddr(HttpServletRequest request) throws Exception {
if (request == null) {
throw (new Exception("getIpAddr method HttpServletRequest Object is null"));
}
String ipString = request.getHeader("x-forwarded-for");
if (StringUtils.isBlank(ipString) || "unknown".equalsIgnoreCase(ipString)) {
ipString = request.getHeader("Proxy-Client-IP");
}
if (StringUtils.isBlank(ipString) || "unknown".equalsIgnoreCase(ipString)) {
ipString = request.getHeader("WL-Proxy-Client-IP");
}
if (StringUtils.isBlank(ipString) || "unknown".equalsIgnoreCase(ipString)) {
ipString = request.getRemoteAddr();
}
// 多个路由时,取第一个非unknown的ip
final String[] arr = ipString.split(",");
for (final String str : arr) {
if (!"unknown".equalsIgnoreCase(str)) {
ipString = str;
break;
}
}
return ipString;
}
}

yml配置文件

#jwt
jwt:
header: Authorization
# 令牌前缀
token-start-with: Bearer
# 使用Base64对该令牌进行编码
base64-secret: 44af5348f21c5ea9d9f80ccc5bddfbf3beebc794b9a4a6258573a841170475a03a03bbd44851882faa0eb2a929ecb0c2e1df12498dafb2764aac83d9d3f5d82d
# 令牌过期时间 此处单位/毫秒-现在是20分钟
token-validity-in-seconds: 1200000

spring security相关java类


JwtAccessDeniedHandler

/**
* @Author Ean
* @Description 没有授权则通过此类返回信息
* @Date 2021/11/18
*/
@Component
public class JwtAccessDeniedHandler implements AccessDeniedHandler {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException {
response.sendError(HttpServletResponse.SC_FORBIDDEN, accessDeniedException.getMessage());
}
}

JwtAuthenticationEntryPoint

/**
* @Author Ean
* @Description 没有权限则通过此类返回信息
* @Date 2021/11/18
*/
@Component
public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request,
HttpServletResponse response,
AuthenticationException authException) throws IOException {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, authException == null ? "Unauthorized" : authException.getMessage());
}
}

UrlAccessDecisionManager

/**
* @author Ean
* @version 0.1.0
* @Description: 该类的作用是判断用户是否有权限访问当前的url
* @return
* @date 2020/8/27 18:06
* @since 0.1.0
*/
@Component
public class UrlAccessDecisionManager implements AccessDecisionManager {
/**
* @param authentication: 当前登录用户的角色信息
* @param object: 请求url信息
* @param collection: `UrlFilterInvocationSecurityMetadataSource`中的getAttributes方法传来的,表示当前请求需要的角色(可能有多个)
* @return: void
*/
@Override
public void decide(Authentication authentication, Object object, Collection collection) throws AccessDeniedException, AuthenticationException {
if (null != authentication && authentication.getCredentials().equals("Yz78r4DSn3yZrSgT")) {//跳过有这个token的请求
return;
}
// 遍历角色
for (ConfigAttribute ca : collection) {
// ① 当前url请求需要的权限
String needRole = ca.getAttribute();
if (Constants.ROLE_LOGIN.equals(needRole)) {
if (authentication instanceof AnonymousAuthenticationToken) {
throw new BadCredentialsException("未登录!");
} else {
throw new AccessDeniedException("未授权该url!");
}
}
// ② 当前用户所具有的角色
Collection authorities = authentication.getAuthorities();
for (GrantedAuthority authority : authorities) {
// 只要包含其中一个角色即可访问
if (authority.getAuthority().equals(needRole)) {
return;
}
}
}
throw new AccessDeniedException("无权访问该接口");
}
@Override
public boolean supports(ConfigAttribute configAttribute) {
return true;
}
@Override
public boolean supports(Class aClass) {
return true;
}
}

UrlAccessDeniedHandler

@Component
public class UrlAccessDeniedHandler implements AccessDeniedHandler {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException e) throws IOException, ServletException {
response.setContentType("application/json");
response.getOutputStream().print(JSONObject.toJSONString(ResultUtil.error(403, "User does not have permission")));
}
}

UrlFilterInvocationSecurityMetadataSource

/**
* @author Ean
* @version 0.1.0
* @Description: 这个类也比较重要。重写的是security的接口权限判断方法。
* getAttributes函数会去数据库查询某个url所需要的权限
* @return
* @date 2020/8/27 18:07
* @since 0.1.0
*/
@Component
public class UrlFilterInvocationSecurityMetadataSource implements FilterInvocationSecurityMetadataSource {
@Autowired
IPermissionService iPermissionService;
@Autowired
IRolePermissionService iRolePermissionService;
@Autowired
IRoleService iRoleService;
AntPathMatcher antPathMatcher = new AntPathMatcher();
/***
* 返回该url所需要的用户权限信息
*
* @param object: 储存请求url信息
* @return: null:标识不需要任何权限都可以访问
*/
@Override
public Collection getAttributes(Object object) throws IllegalArgumentException {
// 获取当前请求url
String requestUrl = ((FilterInvocation) object).getRequestUrl();
/*放行匿名URL*/
if (includeUrl(requestUrl)) {
return null;
}
// 数据库中所有url
Permission[] list = iPermissionService.list(new QueryWrapper

().ne("pid", -1)).toArray(new Permission[0]);
for (Permission permission : list) {
if (null != permission && antPathMatcher.match(permission.getUrl(), requestUrl)) {
RolePermission[] rolePermissiOns= iRolePermissionService.list(new QueryWrapper().eq("permission_id", permission.getPermissionId())).toArray(new RolePermission[0]);
String[] roles = new String[rolePermissions.length];
int i = 0;
if (rolePermissions.length != 0) {
Role role;
for (RolePermission rolePermission : rolePermissions) {
role = iRoleService.getById(rolePermission.getRoleId());
roles[i++] = role.getRoleTitle();
}
}
if (roles.length == 0) {
roles = new String[]{Constants.ROLE_LOGIN};
}
// 保存该url对应角色权限信息
return SecurityConfig.createList(roles);
}
}
// 如果数据中没有找到相应url资源则为非法访问,要求用户登录再进行操作
String[] roleArr = {"user"};//默认角色都是user
return SecurityConfig.createList(roleArr);
}
private boolean includeUrl(String requestUrl) {
AntPathMatcher antPathMatcher = new AntPathMatcher();
boolean flag;
for (Permission permission : WebSecurityConfig.getANNO_URL_LIST()) {
flag = antPathMatcher.match(permission.getUrl(), requestUrl);
if (flag) {
return true;
}
}
return false;
}
@Override
public Collection getAllConfigAttributes() {
return null;
}
@Override
public boolean supports(Class aClass) {
return FilterInvocation.class.isAssignableFrom(aClass);
}
}

过滤器配置


WebSecurityConfig


/**
* @Author Ean
* @Description 总过滤器
* @Date 2021/11/18
*/
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
private final JwtAccessDeniedHandler jwtAccessDeniedHandler;
private final JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint;
private final JwtTokenUtils jwtTokenUtils;
public static List

ANNO_URL_LIST = new ArrayList();
/*获取匿名可访问数组*/
public static List

getANNO_URL_LIST() {
if (ANNO_URL_LIST.size() <= 0) {
IPermissionService iPermissiOnService= (IPermissionService) SpringContextUtil.getBean(IPermissionService.class);
ANNO_URL_LIST = iPermissionService.list(new QueryWrapper

().eq("pid", -1));
}
return ANNO_URL_LIST;
}
/*更新匿名可访问数组*/
public static void flushANNO_URL_LIST() {
IPermissionService iPermissiOnService= (IPermissionService) SpringContextUtil.getBean(IPermissionService.class);
ANNO_URL_LIST = iPermissionService.list(new QueryWrapper

().eq("pid", -1));
}
/**
* 获取访问url所需要的角色信息
*/
private final UrlFilterInvocationSecurityMetadataSource urlFilterInvocationSecurityMetadataSource;
/**
* 认证权限处理 - 将上面所获得角色权限与当前登录用户的角色做对比,如果包含其中一个角色即可正常访问
*/
private final UrlAccessDecisionManager urlAccessDecisionManager;
/**
* 自定义访问无权限接口时403响应内容
*/
private final UrlAccessDeniedHandler urlAccessDeniedHandler;
public WebSecurityConfig(JwtAccessDeniedHandler jwtAccessDeniedHandler, JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint, JwtTokenUtils jwtTokenUtils, UrlFilterInvocationSecurityMetadataSource urlFilterInvocationSecurityMetadataSource, UrlAccessDecisionManager urlAccessDecisionManager, UrlAccessDeniedHandler urlAccessDeniedHandler) {
this.jwtAccessDeniedHandler = jwtAccessDeniedHandler;
this.jwtAuthenticatiOnEntryPoint= jwtAuthenticationEntryPoint;
this.jwtTokenUtils = jwtTokenUtils;
this.urlFilterInvocatiOnSecurityMetadataSource= urlFilterInvocationSecurityMetadataSource;
this.urlAccessDecisiOnManager= urlAccessDecisionManager;
this.urlAccessDeniedHandler = urlAccessDeniedHandler;
}
@Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity.cors().and()
// 禁用 CSRF
.csrf().disable()
// 授权异常
.exceptionHandling()
.authenticationEntryPoint(jwtAuthenticationEntryPoint)
.accessDeniedHandler(jwtAccessDeniedHandler)
// 防止iframe 造成跨域
.and()
.headers()
.frameOptions()
.disable()
// 不创建会话
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
// 所有请求都需要认证
.anyRequest().authenticated().withObjectPostProcessor(new ObjectPostProcessor() {
@Override
public O postProcess(O o) {
o.setSecurityMetadataSource(urlFilterInvocationSecurityMetadataSource);
o.setAccessDecisionManager(urlAccessDecisionManager);
return o;
}
});
;
// 登录过后访问无权限的接口时自定义403响应内容
httpSecurity.exceptionHandling().accessDeniedHandler(urlAccessDeniedHandler);
;
// 登录过后访问无权限的接口时自定义403响应内容
httpSecurity.exceptionHandling().accessDeniedHandler(urlAccessDeniedHandler);
// 禁用缓存
httpSecurity.headers().cacheControl();
// 添加JWT filter
httpSecurity.apply(new TokenConfigurer(jwtTokenUtils));
}
public static class TokenConfigurer extends SecurityConfigurerAdapter {
private final JwtTokenUtils jwtTokenUtils;
public TokenConfigurer(JwtTokenUtils jwtTokenUtils) {
this.jwtTokenUtils = jwtTokenUtils;
}
@Override
public void configure(HttpSecurity http) {
JwtAuthenticationTokenFilter customFilter = new JwtAuthenticationTokenFilter(jwtTokenUtils);
http.addFilterBefore(customFilter, UsernamePasswordAuthenticationFilter.class);
}
}
}

CorsConfigure

/**
* @Author Ean
* @Description 跨域配置
* @Date 2021/11/18
*/
@Configuration
public class CorsConfigure {
@Bean
public CorsConfigurationSource corsConfigurationSource() {
MySecurityProperties mySecurityProperties = new MySecurityProperties();
CorsConfiguration corsCOnfiguration= new CorsConfiguration();
corsConfiguration.setAllowedHeaders(mySecurityProperties.corsAllowedHeaders);
corsConfiguration.setAllowedMethods(mySecurityProperties.corsAllowedMethods);
corsConfiguration.setAllowedOrigins(mySecurityProperties.corsAllowedOrigins);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration(mySecurityProperties.corsPath, corsConfiguration);
return source;
}
private class MySecurityProperties {
/*允许跨域的资源路径*/
private String corsPath;
/*允许跨域的请求头*/
private List corsAllowedHeaders;
/*允许跨域的方法*/
private List corsAllowedMethods;
/*允许跨的站点*/
private List corsAllowedOrigins;
private final List CORS_ALLOWED_HEADERS = Arrays.asList("Authorization", "Content-type");
private final List CORS_ALLOWED_METHODS = Arrays.asList("GET", "POST", "PUT", "DELETE");
public MySecurityProperties() {
this.corsPath = "/**";
this.corsAllowedHeaders = CORS_ALLOWED_HEADERS;
this.corsAllowedMethods = CORS_ALLOWED_METHODS;
this.corsAllowedOrigins = Arrays.asList("*");
}
}
}

JwtAuthenticationTokenFilter

/**
* @author Ean
* @version 0.1.0
* @Description: 重点过滤器,该过滤器拦截请求,并校验token。通过则提取角色信息交给security处理
* @return
* @date 2020/8/27 18:05
* @since 0.1.0
*/
@Component
@Slf4j
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
private JwtTokenUtils jwtTokenUtils;
public JwtAuthenticationTokenFilter(JwtTokenUtils jwtTokenUtils) {
this.jwtTokenUtils = jwtTokenUtils;
}
@Override
protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {
JwtSecurityProperties jwtSecurityProperties = (JwtSecurityProperties) SpringContextUtil.getBean(JwtSecurityProperties.class);
String requestRri = httpServletRequest.getRequestURI();
//获取request token
String token = null;
String bearerToken = httpServletRequest.getHeader(jwtSecurityProperties.getHeader());
if (null!=bearerToken&&bearerToken.equals("Yz78r4DSn3yZrSgT")) {//忽略带有此token的请求
Authentication authentication = jwtTokenUtils.getAuthentication(bearerToken, httpServletRequest);
SecurityContextHolder.getContext().setAuthentication(authentication);
}
if (StringUtils.hasText(bearerToken) && bearerToken.startsWith(jwtSecurityProperties.getTokenStartWith())) {
token = bearerToken.substring(jwtSecurityProperties.getTokenStartWith().length());
}
/*访问接口的时候,判断token是否有效并从token里边提取用户信息跟角色记录到此次请求中*/
if (StringUtils.hasText(token) && jwtTokenUtils.validateToken(token,httpServletRequest)) {
Authentication authentication = jwtTokenUtils.getAuthentication(token,httpServletRequest);
SecurityContextHolder.getContext().setAuthentication(authentication);
log.debug("set Authentication to security context for '{}', uri: {}", authentication.getName(), requestRri);
} else {
log.debug("no valid JWT token found, uri: {}", requestRri);
}
filterChain.doFilter(httpServletRequest, httpServletResponse);
}
}

授权控制器


AuthController

@Slf4j
@RestController
@RequestMapping("/api/auth")
@Api(tags = "系统授权接口")
public class AuthController {
private final JwtTokenUtils jwtTokenUtils;
final
IPermissionService iPermissionService;
final
IUserService userService;
public AuthController(JwtTokenUtils jwtTokenUtils, IPermissionService iPermissionService, IUserService userService) {
this.jwtTokenUtils = jwtTokenUtils;
this.iPermissiOnService= iPermissionService;
this.userService = userService;
}
@ApiOperation("登录授权")
@PostMapping(value = "/login")
public Result login(String uAcco, String uPass, HttpServletRequest httpServletRequest) {
Map resMap = userService.checkAndGetToken(uAcco, uPass,httpServletRequest);
if (null != resMap) {
return ResultUtil.success(resMap);
}
return ResultUtil.error(-1, "用户名密码错误");
}
@ApiOperation("刷新匿名url")
@GetMapping("flushANNO_URL")
public String flushANNO_URL() {
IPermissionService iPermissiOnService= (IPermissionService) SpringContextUtil.getBean(IPermissionService.class);
List

ANNO_URL_LIST = iPermissionService.list(new QueryWrapper

().eq("pid", -1));
WebSecurityConfig.ANNO_URL_LIST = ANNO_URL_LIST;
return "flush ok";
}
}

checkAndGetToken

@Override
public Map checkAndGetToken(String uAcco, String uPass, HttpServletRequest servletRequest) {
String ip="";
try {
ip = IpUtils.getIpAddr(servletRequest);
} catch (Exception e) {
e.printStackTrace();
}
User user = this.getOne(new QueryWrapper().eq("u_acco", uAcco).eq("u_pass", uPass));
if (null != user) {
Map param = new HashMap();
param.put("username", uAcco);
param.put("password", uPass);
param.put("ip", ip);
String[] roleTitle = roleMapper.getRoleTitle(user.getUserId());
if (roleTitle.length > 0) {
param.put("roles", StringUtils.join(roleTitle, ","));
}
Map res = new HashMap();
res.put("Authorization", jwtTokenUtils.createToken(param));
res.put("user", user);
return res;
}
return null;
}

pom文件



org.springframework.boot
spring-boot-starter-security



io.jsonwebtoken
jjwt-api
0.10.6


io.jsonwebtoken
jjwt-impl
0.10.6


io.jsonwebtoken
jjwt-jackson
0.10.6


原文链接:https://www.cnblogs.com/eangaie/p/15577657.html



推荐阅读
  • Spring特性实现接口多类的动态调用详解
    本文详细介绍了如何使用Spring特性实现接口多类的动态调用。通过对Spring IoC容器的基础类BeanFactory和ApplicationContext的介绍,以及getBeansOfType方法的应用,解决了在实际工作中遇到的接口及多个实现类的问题。同时,文章还提到了SPI使用的不便之处,并介绍了借助ApplicationContext实现需求的方法。阅读本文,你将了解到Spring特性的实现原理和实际应用方式。 ... [详细]
  • Spring源码解密之默认标签的解析方式分析
    本文分析了Spring源码解密中默认标签的解析方式。通过对命名空间的判断,区分默认命名空间和自定义命名空间,并采用不同的解析方式。其中,bean标签的解析最为复杂和重要。 ... [详细]
  • 在重复造轮子的情况下用ProxyServlet反向代理来减少工作量
    像不少公司内部不同团队都会自己研发自己工具产品,当各个产品逐渐成熟,到达了一定的发展瓶颈,同时每个产品都有着自己的入口,用户 ... [详细]
  • 本文介绍了lua语言中闭包的特性及其在模式匹配、日期处理、编译和模块化等方面的应用。lua中的闭包是严格遵循词法定界的第一类值,函数可以作为变量自由传递,也可以作为参数传递给其他函数。这些特性使得lua语言具有极大的灵活性,为程序开发带来了便利。 ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • 本文介绍了OC学习笔记中的@property和@synthesize,包括属性的定义和合成的使用方法。通过示例代码详细讲解了@property和@synthesize的作用和用法。 ... [详细]
  • 本文主要解析了Open judge C16H问题中涉及到的Magical Balls的快速幂和逆元算法,并给出了问题的解析和解决方法。详细介绍了问题的背景和规则,并给出了相应的算法解析和实现步骤。通过本文的解析,读者可以更好地理解和解决Open judge C16H问题中的Magical Balls部分。 ... [详细]
  • 知识图谱——机器大脑中的知识库
    本文介绍了知识图谱在机器大脑中的应用,以及搜索引擎在知识图谱方面的发展。以谷歌知识图谱为例,说明了知识图谱的智能化特点。通过搜索引擎用户可以获取更加智能化的答案,如搜索关键词"Marie Curie",会得到居里夫人的详细信息以及与之相关的历史人物。知识图谱的出现引起了搜索引擎行业的变革,不仅美国的微软必应,中国的百度、搜狗等搜索引擎公司也纷纷推出了自己的知识图谱。 ... [详细]
  • http:my.oschina.netleejun2005blog136820刚看到群里又有同学在说HTTP协议下的Get请求参数长度是有大小限制的,最大不能超过XX ... [详细]
  • 自动轮播,反转播放的ViewPagerAdapter的使用方法和效果展示
    本文介绍了如何使用自动轮播、反转播放的ViewPagerAdapter,并展示了其效果。该ViewPagerAdapter支持无限循环、触摸暂停、切换缩放等功能。同时提供了使用GIF.gif的示例和github地址。通过LoopFragmentPagerAdapter类的getActualCount、getActualItem和getActualPagerTitle方法可以实现自定义的循环效果和标题展示。 ... [详细]
  • 预备知识可参考我整理的博客Windows编程之线程:https:www.cnblogs.comZhuSenlinp16662075.htmlWindows编程之线程同步:https ... [详细]
  • 2018深入java目标计划及学习内容
    本文介绍了作者在2018年的深入java目标计划,包括学习计划和工作中要用到的内容。作者计划学习的内容包括kafka、zookeeper、hbase、hdoop、spark、elasticsearch、solr、spring cloud、mysql、mybatis等。其中,作者对jvm的学习有一定了解,并计划通读《jvm》一书。此外,作者还提到了《HotSpot实战》和《高性能MySQL》等书籍。 ... [详细]
  • 基于Socket的多个客户端之间的聊天功能实现方法
    本文介绍了基于Socket的多个客户端之间实现聊天功能的方法,包括服务器端的实现和客户端的实现。服务器端通过每个用户的输出流向特定用户发送消息,而客户端通过输入流接收消息。同时,还介绍了相关的实体类和Socket的基本概念。 ... [详细]
  • 先看一段错误日志:###Errorqueryingdatabase.Cause:com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransie ... [详细]
  • SpringBoot整合SpringSecurity+JWT实现单点登录
    SpringBoot整合SpringSecurity+JWT实现单点登录,Go语言社区,Golang程序员人脉社 ... [详细]
author-avatar
别禳莴觞芯_737
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有