Spring boot 与 spring Security 结合JWT实现动态权限管理

本文介绍如何在SpringBoot项目中结合SpringSecurity和JWT实现动态权限管理,包括配置、自定义过滤器、权限验证及登录认证流程。通过具体代码示例,详细展示了如何设置权限URL、生成和验证token,以及如何进行用户权限检查。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

spring boot 与spring security 结合jwt实现动态权限管理

网上搜索的东西太杂太乱了,所以自己整了一下发给大家,仅供借鉴,原理什么的不做过多解释,流程什么的都在代码注释里
密码加密什么的没有做,直接用的明文密码,没有加密,太懒了
基本的mysql啥的不做过多解释

权限url写在数据库中
登录的话会把登录信息放入security 缓存中,
并且生成一个token,存储用户信息
在这里插入图片描述
访问受保护的url时需要带上token信息
如果不带入token则会返回空也就是没有权限
查询yml配置,如果是不需要拦截的,直接放行,否则会查询该用户所拥有的权限,如果不存在则返回403
在这里插入图片描述
在这里插入图片描述

sql表

sql


/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET NAMES utf8 */;
/*!50503 SET NAMES utf8mb4 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;

-- 导出  表 test.menu 结构
CREATE TABLE IF NOT EXISTS `menu` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `url` varchar(50) DEFAULT NULL,
  `role_id` varchar(50) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;

-- 正在导出表  test.menu 的数据:~2 rows (大约)
/*!40000 ALTER TABLE `menu` DISABLE KEYS */;
INSERT INTO `menu` (`id`, `url`, `role_id`) VALUES
	(1, '/account/all\r\n', '1'),
	(2, '/account/abc', '1');
/*!40000 ALTER TABLE `menu` ENABLE KEYS */;

-- 导出  表 test.role 结构
CREATE TABLE IF NOT EXISTS `role` (
  `id` int(11) DEFAULT NULL,
  `name` varchar(50) DEFAULT NULL,
  `user_id` bigint(20) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- 正在导出表  test.role 的数据:~1 rows (大约)
/*!40000 ALTER TABLE `role` DISABLE KEYS */;
INSERT INTO `role` (`id`, `name`, `user_id`) VALUES
	(1, 'admin', 1);
/*!40000 ALTER TABLE `role` ENABLE KEYS */;

-- 导出  表 test.user 结构
CREATE TABLE IF NOT EXISTS `user` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `username` varchar(50) NOT NULL DEFAULT '0',
  `password` varchar(200) NOT NULL DEFAULT '0.00',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;

-- 正在导出表  test.user 的数据:~2 rows (大约)
/*!40000 ALTER TABLE `user` DISABLE KEYS */;
INSERT INTO `user` (`id`, `username`, `password`) VALUES
	(1, 'admin', '123'),
	(2, 'admini', '123');
/*!40000 ALTER TABLE `user` ENABLE KEYS */;

/*!40101 SET SQL_MODE=IFNULL(@OLD_SQL_MODE, '') */;
/*!40014 SET FOREIGN_KEY_CHECKS=IF(@OLD_FOREIGN_KEY_CHECKS IS NULL, 1, @OLD_FOREIGN_KEY_CHECKS) */;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;

POM

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>spring_security</groupId>
	<artifactId>spring_security</artifactId>
	<version>1.0.0</version>
	<name>spring_security</name>
	<!-- Spring Boot 启动父依赖 -->
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>1.5.4.RELEASE</version>
	</parent>
	<!-- 定义引入的POM包的版本号 -->
	<properties>
		<mybatis-spring-boot>1.2.0</mybatis-spring-boot>
		<mysql-connector>5.1.39</mysql-connector>
		<druid>1.0.18</druid>
		<java.version>1.8</java.version>
		<shiro-spring>1.4.0</shiro-spring>
		<java-jwt>3.4.0</java-jwt>
	</properties>

	<dependencies>

		<!-- Spring Boot Web 依赖 -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
			<exclusions>
				<exclusion>
					<groupId>com.fasterxml.jackson.core</groupId>
					<artifactId>jackson-databind</artifactId>
				</exclusion>
			</exclusions>
		</dependency>
		<!-- =============================================== -->
		

		<dependency>
			<groupId>
			org.springframework.boot
			</groupId>
			<artifactId>
			spring-boot-starter-security
			</artifactId>
		</dependency>
		<!-- 监控 -->
		<!-- <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-actuator</artifactId> 
			</dependency> -->
		<dependency>
			<groupId>io.jsonwebtoken</groupId>
			<artifactId>jjwt</artifactId>
			<version>0.9.0</version>
		</dependency>
		<!-- =============================================== -->
		<!-- Spring Boot Mybatis 依赖 -->
		<dependency>
			<groupId>org.mybatis.spring.boot</groupId>
			<artifactId>mybatis-spring-boot-starter</artifactId>
			<version>1.1.1</version>
		</dependency>
		<!-- https://mvnrepository.com/artifact/commons-logging/commons-logging -->
		<dependency>
			<groupId>commons-logging</groupId>
			<artifactId>commons-logging</artifactId>
			<version>1.2</version>
		</dependency>

		<!-- MySQL 连接驱动依赖 -->
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>${mysql-connector}</version>
		</dependency>

		<!-- Druid 数据连接池依赖 -->
		<dependency>
			<groupId>com.alibaba</groupId>
			<artifactId>druid</artifactId>
			<version>${druid}</version>
		</dependency>

		<!-- 分页插件 -->
		<dependency>
			<groupId>com.github.pagehelper</groupId>
			<artifactId>pagehelper</artifactId>
			<version>4.1.6</version>
		</dependency>
		<!-- 返回html页面 -->
		<!-- <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-freemarker</artifactId> 
			</dependency> -->
		<dependency>
			<groupId>com.alibaba</groupId>
			<artifactId>fastjson</artifactId>
			<version>1.2.47</version>
		</dependency>
		<!-- springboot热部署 -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-devtools</artifactId>
			<optional>true</optional><!--true时热部署才会生效,可以不用写配置文件 -->
		</dependency>
		<!-- 代码生成 -->
		<dependency>
			<groupId>org.mybatis.generator</groupId>
			<artifactId>mybatis-generator-core</artifactId>
			<version>1.3.7</version>
		</dependency>
	</dependencies>
	<!-- 开启热部署 -->
	<build>
		<plugins>
			<!-- =========================================== -->
			<!-- spring热部署 -->
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
				<dependencies>
					<dependency>
						<groupId>org.springframework</groupId>
						<artifactId>springloaded</artifactId>
						<version>1.2.6.RELEASE</version>
					</dependency>
				</dependencies>
			</plugin>
			<!-- ===================================== -->
			<!-- Srping Boot 打包工具 -->
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
				<version>1.5.7.RELEASE</version>
				<executions>
					<execution>
						<goals>
							<goal>repackage</goal>
						</goals>
					</execution>
				</executions>
			</plugin>
			<!-- ===================================== -->
			<!-- 指定JDK编译版本 -->
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<configuration>
					<source>1.8</source>
					<target>1.8</target>
					<encoding>UTF-8</encoding>
				</configuration>
			</plugin>
			<!-- ===================================== -->
		</plugins>
	</build>
</project>

yml

server:
  port: 8082

logging:
  level: 
    learning: trace
spring:
  #数据源配置
  datasource:
    url: jdbc:mysql://localhost:3306/test
    username: root
    password: root
    driver-class-name: com.mysql.jdbc.Driver
    type: com.alibaba.druid.pool.DruidDataSource
    connectionProperties: druid.stat.mergeSql=true
    maxActive: 100
    initialSize: 10
    minIdle: 5
    testWhileIdle: true
    timeBetweenEvictionRunsMillis: 60000
    minEvictableIdleTimeMillis: 30000
    validationQuery: SELECT 1
http: 
   encoding: 
   charset: UTF-8
jwt: 
   path: /user/**,/account/b
   header: Authorization
   secretkey: WZH1998&1998
   expiration: 8640000000 
   authPrefix: auth

基础类
JwtProperties 权限配置类
JwtUser安全用户类型 需要实现 UserDetails
RoleUrlJWt 管理权限的 实现GrantedAuthority类

package com.qsh.filter;

import java.security.Key;

import javax.crypto.spec.SecretKeySpec;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

import io.jsonwebtoken.SignatureAlgorithm;
@Component
@ConfigurationProperties(prefix="jwt")  // jwt begin.
public class JwtProperties {
	//header参数名
		private  String header;
		//过期毫秒数
		private Long expiration;
		private  String secretkey;
		
		private  String path;
		
		private String authPrefix;
		
		public String getAuthPrefix() {
			return authPrefix;
		}
		public void setAuthPrefix(String authPrefix) {
			this.authPrefix = authPrefix;
		}
		public String getHeader() {
			return header;
		}
		public void setHeader(String header) {
			this.header = header;
		}
		public Long getExpiration() {
			return expiration;
		}
		public void setExpiration(Long expiration) {
			this.expiration = expiration;
		}
		public String getSecretkey() {
			return secretkey;
		}
		public void setSecretkey(String secretkey) {
			this.secretkey = secretkey;
		}
		public String getPath() {
			return path;
		}
		public void setPath(String path) {
			this.path = path;
		}
		public Key getSecrt() {
			return new SecretKeySpec(secretkey.getBytes(),
					SignatureAlgorithm.HS512.getJcaName());
		}
}
=========================================================================================================
package com.qsh.filter;

import java.util.Collection;

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

import com.alibaba.fastjson.annotation.JSONField;

/**
 * 安全用户类型 需要实现 UserDetails
 * @author Administrator
 *
 */
@SuppressWarnings("all")
@Component
public class JwtUser implements UserDetails{
	private Long id;
	private String username;
	private String password;
	 private Collection<? extends GrantedAuthority> authorities;//权限集合
	 
	/**
	 * id:主键
	 *
	 * @return  the id
	 * @since    Ver 1.0
	*/
	
	public Long getId() {
		return id;
	}



	/**
	 * 返回用户的角色列表
	 */
	@Override
	public Collection<? extends GrantedAuthority> getAuthorities() {
		
		// TODO Auto-generated method stub
		return authorities;
		
	}

	/**
	 * 账户密码:禁用序列化
	 */
	@JSONField(serialize=false)
	@Override
	public String getPassword() {
		
		// TODO Auto-generated method stub
		return password;
		
	}

	/**
	 * 用户账号
	 */
	@Override
	public String getUsername() {
		
		// TODO Auto-generated method stub
		return username;
		
	}

	/**
	 * 账号是否未过期
	 */
	@Override
	public boolean isAccountNonExpired() {
		
		// TODO Auto-generated method stub
		return false;
		
	}

	/**
	 * 账号是否锁定
	 */
	@Override
	public boolean isAccountNonLocked() {
		
		// TODO Auto-generated method stub
		return false;
		
	}

	/**
	 * 密码是否未过期
	 */
	@Override
	public boolean isCredentialsNonExpired() {
		
		// TODO Auto-generated method stub
		return false;
		
	}

	/**
	 * 账号是否可用
	 */
	@Override
	public boolean isEnabled() {
		
		// TODO Auto-generated method stub
		return false;
		
	}
	
	
	public void setUsername(String username) {
		this.username = username;
	}
	public void setPassword(String password) {
		this.password = password;
	}
	public void setAuthorities(Collection<? extends GrantedAuthority> authorities) {
		this.authorities = authorities;
	}
	
	public JwtUser() {
		super();
	}
	
	public JwtUser(String username) {
		super();
		this.username = username;
	}
	public JwtUser(String username, String password) {
		super();
		this.username = username;
		this.password = password;
	}
	public JwtUser(String username, String password, Collection<? extends GrantedAuthority> authorities) {
		super();
		this.username = username;
		this.password = password;
		this.authorities = authorities;
	}



	public JwtUser(Long id, String username, String password, Collection<? extends GrantedAuthority> authorities) {
		super();
		this.id = id;
		this.username = username;
		this.password = password;
		this.authorities = authorities;
	}



	public JwtUser(String id, String username, String password, Collection<? extends GrantedAuthority> authorities) {
		super();
		this.id = Long.valueOf(id);
		this.username = username;
		this.password = password;
		this.authorities = authorities;
	}


@Override
public String toString() {
	// TODO Auto-generated method stub
	return super.toString();
}

}
==============================================================================================================
package com.qsh.filter;

import org.springframework.security.core.GrantedAuthority;
import org.springframework.stereotype.Component;

/**
 * 管理权限的 实现GrantedAuthority类
 * 重写equals,toString
 * @author Administrator
 *
 */
@Component
public final class RoleUrlJWt implements GrantedAuthority{
	private  String url;
	@Override
	public String getAuthority() {
		// TODO Auto-generated method stub
		return url;
	}
	public RoleUrlJWt(String url) {
		super();
		this.url = url;
	}
	public String getUrl() {
		return url;
	}
	public void setUrl(String url) {
		this.url = url;
	}
	public RoleUrlJWt() {
		super();
	}
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((url == null) ? 0 : url.hashCode());
		return result;
	}
	public String toString() {
		return this.url;
	}
	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		RoleUrlJWt other = (RoleUrlJWt) obj;
		if (url == null) {
			if (other.url != null)
				return false;
		} else if (!url.equals(other.url))
			return false;
		return true;
	}
	
}

1:继承WebSecurityConfigurerAdapter类 配置默认过滤器

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.stereotype.Component;
import org.springframework.web.cors.CorsUtils;

import com.qsh.filter.renzheng.WZHFilterSecurityInterceptor;

/**
 * 注意  protected void configure(AuthenticationManagerBuilder auth) throws Exception { 方法中
 * 密码校验具有加密和不加密两种情况,所谓加密是值,前台传递来的是明文,后台被比较的-从数据库取出来的密码是明文加密后存储的,
 * 这样需要将前台明文密码加密后和数据库存储的密码进行比较,
 * 需要结合 com.bestcxx.stu.springbootsecuritydb.security.service.CustomUserService 类中的注释进行理解 
 * @author wj
 *
 */
@Component
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
	@Autowired
	JWTAuthenticationProvider provider;
	private JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;
	private JwtProperties propersion;
	@Autowired
	  
	  private WZHFilterSecurityInterceptor WZHFilterSecurityInterceptor;
	@Autowired
	public void getJwtAuthenticationTokenFilter(JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter,JwtProperties propersion) {
	 	this.jwtAuthenticationTokenFilter=jwtAuthenticationTokenFilter;
	 	this.propersion=propersion;
	 //	this.myFilterSecurityInterceptor=myFilterSecurityInterceptor;
	}
	
	@Override
	protected void configure(HttpSecurity http) throws Exception {
		http.csrf().disable().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()//后续需配置使用自己的默认登录页等基本设置
		
		   .authorizeRequests().antMatchers(
				   HttpMethod.GET,
				   "/",
	               "/*.html",
	               "/favicon.ico",
	               "/**/*.html",
	               "/**/*.css",
	               "/**/*.js").permitAll()
		    // 对于获取token的rest api要允许匿名访问
		   .requestMatchers(CorsUtils::isPreFlightRequest).permitAll()
		   .antMatchers(propersion.getPath().split(",")).permitAll()
	       .anyRequest().authenticated();
		http.headers().cacheControl();
		// 自定义Filter完成验证码校验
		http.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);//token过滤器
		http.addFilterBefore(WZHFilterSecurityInterceptor, FilterSecurityInterceptor.class);//权限过滤器
	}
	/**
	 * 如果不把验证交给系统则会一直出现账户已被锁定,失效等异常
	 * @param auth
	 * @throws Exception
	 */
	@Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        //将验证过程交给系统验证提供者
        auth.authenticationProvider(provider);
    }
}

2:自定义token拦截器

package com.qsh.filter;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
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.authentication.WebAuthenticationDetailsSource;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.stereotype.Service;
import org.springframework.web.cors.CorsUtils;
import org.springframework.web.filter.OncePerRequestFilter;

import com.qsh.exception.MyException;
import com.qsh.util.JwtHelper;

import io.jsonwebtoken.Claims;

/**
 * Token过滤器
 *
 * @author hackyo Created on 2017/12/8 9:28.
 */
@SuppressWarnings("all")
@Service
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter  {
	@Autowired
	private UserDetailsService userDetailsService;
	@Autowired
	private JwtHelper jwtHelper;
	private JwtProperties porpersion;

	@Autowired
	public JwtProperties getJwtPropersion(JwtProperties propersion) {
		return this.porpersion = propersion;
	}
	
	@Override
	protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
			throws ServletException, IOException {
		//循环匹配看当前访问url是否需要过滤,如果为true标识不需要被拦截的,比如/login
		Boolean aa = this.matchers(porpersion.getPath(), request);
		Boolean bb = CorsUtils.isPreFlightRequest(request);
		if (aa || bb) {
			filterChain.doFilter(request, response);
			return;
		}
		String token = request.getHeader(porpersion.getHeader());
		String tokenHead = "Bearer ";
		if (token != null && token.startsWith(tokenHead)) {
			//执行userDetailsService.loadUserByUsername方法校验用户的正确性
			UserDetails userDetaile = userDetailsService
					.loadUserByUsername(jwtHelper.getUsernameFromToken(token.substring(7)));
			
				try {
					//校验token的安全性
					boolean b = jwtHelper.validateToken(token.substring(7), userDetaile);
					if(b) {
						Claims claims = jwtHelper.getClaimsFromToken(token.substring(7));
						//把当前用户信息放入Security全局缓存中
						SecurityContextHolder.getContext().setAuthentication(getAuth(claims));
						filterChain.doFilter(request, response);
					}
				} catch (MyException e) {

					response.sendError(HttpServletResponse.SC_UNAUTHORIZED, e.getMessage());

				}
		}
	}
	/**
	 * 循环匹配url如果为true,则属于受保护应用不被过滤
	 * @param path
	 * @param request
	 * @return
	 */
	private Boolean matchers(String path, HttpServletRequest request) {
		String[] temp = path.split("[,]");
		Boolean b = false;
		for (String s : temp) {
			AntPathRequestMatcher matcher = new AntPathRequestMatcher(s.trim());

			if (matcher.matches(request)) {
				b = true;
				break;
			} else {
				continue;
			}
		}
		return b;
	}

	private Authentication getAuth(Claims claims) {
		ArrayList<RoleUrlJWt> authorities = new ArrayList<>();
		@SuppressWarnings("unchecked")
		List<Map<String, String>> Auths = (List<Map<String, String>>) claims.get(porpersion.getAuthPrefix());
		for (Map<String, String> authority : Auths) {
			authorities.add(new RoleUrlJWt(authority.get("authority")));
		}
		JwtUser principal = new JwtUser(claims.getId(), claims.getSubject(), "", authorities);
		UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(
				principal, "", authorities);
		return usernamePasswordAuthenticationToken;
	}
}

实现UserDetailsService 重写loadUserByUsername方法
UserDetailsService验证用户名、密码和授权处理。
包含 GrantedAuthority 的 UserDetails对象在构建 Authentication对象时填入数据。

package com.qsh.filter;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

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 com.qsh.entity.User;
import com.qsh.service.UserService;

/**
 *	UserDetailsService验证用户名、密码和授权处理。
 *包含 GrantedAuthority 的 UserDetails对象在构建 Authentication对象时填入数据。
 */
@Service
public class JwtUserDetailsServiceImpl  implements UserDetailsService  {
	@Autowired
	UserService userService;
	/**
	 * 登陆验证时,通过username获取用户的所有权限信息,
	 * 并返回JwtUser放到spring的全局缓存SecurityContextHolder中,以供授权器使用
	 */
	@Override
	public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
		User user = userService.login(username);
		System.err.println("UserDetailsService:loadUserByUsername:"+username);
		if(user == null){
			return null;
		}else {
		//我的是一个用户对应一个角色,一个角色有多个权限
		//通过用户名查询对应的角色
			String role =  userService.getRolesByUserName(username);
			//通过角色查询url并放入GrantedAuthority中
			List<String> set = userService.getPermissionsByRoles(role);
			Collection<GrantedAuthority>  authorities=generateAuthorities(set);
			return new JwtUser(user.getId(),username, user.getPassword(), authorities);
		}
	}
	/**
	 * 把url放入JwtUser权限集合中
	 * @param privileges
	 * @return
	 */
	private Collection<GrantedAuthority> generateAuthorities(Collection<String> privileges) {
		List<GrantedAuthority> auth = new ArrayList<GrantedAuthority>(
				privileges.size());
		for (String privilege : privileges) {
			GrantedAuthority authority = new RoleUrlJWt(
					privilege);
			auth.add(authority);
		}
		return auth;
	}


}

以上为登录验证的

下面是每次访问鉴权

访问受保护的权限

  • 访问受保护url时,会通过AbstractSecurityInterceptor拦截器拦截
  • 其中会调用FilterInvocationSecurityMetadataSource的方法来获取被拦截url所需的全部权限
  • 在调用授权管理器AccessDecisionManager,这个授权管理器会通过spring的全局缓存SecurityContextHolder获取用户的权限信息,
  • 还会获取被拦截的url和被拦截url所需的全部权限,然后根据所配的策略(有:一票决定,一票否定,少数服从多数等),如果权限足够,则返回,权限不够则报错并调用权限不足页面。
package com.qsh.filter.renzheng;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

import org.springframework.beans.factory.annotation.Autowired;
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.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import org.springframework.stereotype.Service;

/**
 * 访问受保护的权限第一步
 * 
 * 访问受保护url时,会通过AbstractSecurityInterceptor拦截器拦截
 * 其中会调用FilterInvocationSecurityMetadataSource的方法来获取被拦截url所需的全部权限
 * 在调用授权管理器AccessDecisionManager,这个授权管理器会通过spring的全局缓存SecurityContextHolder获取用户的权限信息,
 * 还会获取被拦截的url和被拦截url所需的全部权限,然后根据所配的策略(有:一票决定,一票否定,少数服从多数等),如果权限足够,则返回,权限不够则报错并调用权限不足页面。
 * @author Administrator
 *
 */
@Service
public class WZHFilterSecurityInterceptor extends AbstractSecurityInterceptor implements Filter {
	
	
	@Autowired
	private FilterInvocationSecurityMetadataSource securityMetadataSource;
	
	
    @Autowired
    public void setLYJAccessDecisionManager(WZHAccessDecisionManager lyjAccessDecisionManager) {
        super.setAccessDecisionManager(lyjAccessDecisionManager);
    }

	@Override
	public void init(FilterConfig filterConfig) throws ServletException {
		
	}
	//登陆后,每次访问资源都通过这个拦截器拦截
	@Override
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
			throws IOException, ServletException {

		 FilterInvocation filterInvocation = new FilterInvocation(request, response, chain);
		//filterInvocation里面有一个被拦截的url
	        //里面调用WZHMetadataSource.java的getAttributes(Object object)这个方法获取fi对应的所有权限
	        //再调用WZHAccessDecisionManager.java的decide方法来校验用户的权限是否足够
	     InterceptorStatusToken token = super.beforeInvocation(filterInvocation);
	     try {
	    	//执行下一个拦截器
	    	 filterInvocation.getChain().doFilter(filterInvocation.getRequest(), filterInvocation.getResponse());
	     } finally {
	            super.afterInvocation(token, null);
	     }
	}

	@Override
	public void destroy() {
		// TODO Auto-generated method stub
		
	}

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

	@Override
	public SecurityMetadataSource obtainSecurityMetadataSource() {
		// TODO Auto-generated method stub
		return this.securityMetadataSource;
	}

}
================================================================================================
package com.qsh.filter.renzheng;

import java.util.Collection;
import java.util.HashSet;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;

import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import org.springframework.stereotype.Service;
/**
 * 访问受保护的权限第二步
 * 
 * FilterInvocationSecurityMetadataSource的方法来获取被拦截url所需的全部权限
 * @author Administrator
 *
 */
@Service
public class WZHMetadataSource implements FilterInvocationSecurityMetadataSource{
	//参数是要访问的url,返回这个url对于的所有权限(或角色)
	@Override
	public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException {
        final HttpServletRequest request = ((FilterInvocation) object).getRequest();
        Set<ConfigAttribute> allAttributes = new HashSet<ConfigAttribute>();
        ConfigAttribute configAttribute = new WZHConfigAttribute(request);
        allAttributes.add(configAttribute);
        return allAttributes;
	}

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

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

}
================================================================================================
/**
 * LYJAccessDecisionManager.java
 * com.lyj.springboot.footstone.security.decision
 * Function: TODO add descript
 *
 *   ver     date      		author
 * ──────────────────────────────────
 *   		 2017年10月30日       lyj
 *
 * Copyright (c) 2017, TNT All Rights Reserved.
*/

package com.qsh.filter.renzheng;

import java.util.Collection;

import javax.servlet.http.HttpServletRequest;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.AccessDecisionManager;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.authentication.InsufficientAuthenticationException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.stereotype.Service;
import org.springframework.web.cors.CorsUtils;

import com.qsh.filter.JwtProperties;
import com.qsh.filter.RoleUrlJWt;


/**
 * 第三步
 *  授权管理器AccessDecisionManager,这个授权管理器会通过spring的全局缓存SecurityContextHolder获取用户的权限信息,
 * 还会获取被拦截的url和被拦截url所需的全部权限,然后根据所配的策略(有:一票决定,一票否定,少数服从多数等),如果权限足够,则返回,权限不够则报错并调用权限不足页面。
 */
@Service
public class WZHAccessDecisionManager implements AccessDecisionManager {
	@Autowired
	JwtProperties jwtProperties;
	//检查用户是否够权限访问资源
    //参数authentication是从spring的全局缓存SecurityContextHolder中拿到的,里面是用户的权限信息
    //参数object是url
    //参数configAttributes所需的权限
	@Override
	public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes)
			throws AccessDeniedException, InsufficientAuthenticationException {
		
        HttpServletRequest request = ((FilterInvocation) object).getHttpRequest();
        
        if(matchers("/",request) || matchers("/*.html",request) || matchers("/favicon.ico", request) || matchers("/**/*.css", request) || matchers("/**/*.js", request) 
        		 || matchers(jwtProperties.getPath(), request) || CorsUtils.isPreFlightRequest(request)){
        	
        	
        	
        	return;
        	
        }else{
        	
        	for(GrantedAuthority grant : authentication.getAuthorities()){
        		
        		if(grant instanceof RoleUrlJWt){
        			
        			String url = ((RoleUrlJWt)grant).getAuthority();
        			
        			if(matchers(url, request)){
        				
        				return;
        			}
        		}
        		
        	}
        }
      //注意:执行这里,后台是会抛异常的,但是界面会跳转到所配的access-denied-page页面
      throw new AccessDeniedException("You do not have permission !");

	}

	/**
	 * @see org.springframework.security.access.AccessDecisionManager#supports(org.springframework.security.access.ConfigAttribute)
	 */
	@Override
	public boolean supports(ConfigAttribute attribute) {
		
		return true;
		
	}

	/**
	 * @see org.springframework.security.access.AccessDecisionManager#supports(java.lang.Class)
	 */
	@Override
	public boolean supports(Class<?> clazz) {
		
		return true;
		
	}
    
    /**
     * 循环匹配url
     * @param path
     * @param request
     * @return
     */
    private Boolean matchers(String path,HttpServletRequest request) {
    	
    	String[] temp = path.split("[,]");
    	
    	Boolean b  = false;
    	
    	for(String s : temp) {
    		
            AntPathRequestMatcher matcher = new AntPathRequestMatcher(s.trim());

            if(matcher.matches(request)) {
            	b = true;
            	break;
            }else {
            	
            	continue;
            }
    	}
    	
    	return b;

		
	}

}
=====================================================================================================
package com.qsh.filter.renzheng;

import javax.servlet.http.HttpServletRequest;

import org.springframework.security.access.ConfigAttribute;

/**
 * @author
 *	
 */
public class WZHConfigAttribute implements ConfigAttribute{
	
	
	private static final long serialVersionUID = 9155663980275938220L;
	
	
	private final HttpServletRequest httpServletRequest;
	
	public  WZHConfigAttribute(HttpServletRequest httpServletRequest) {
		
		
		this.httpServletRequest = httpServletRequest;
		
	}

	@Override
	public String getAttribute() {
		// TODO Auto-generated method stub
		return null;
	}
	

    public HttpServletRequest getHttpServletRequest() {
        return httpServletRequest;
    }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值