springboot+springSecurity+mybatis实现权限管理
来源:互联网 发布:美服战网客户端mac 编辑:程序博客网 时间:2024/05/22 01:36
数据库设计
说明:
1.用户可以对应多个角色,角色可以对应多个权限;
2.PermissionAccess对应menu,button,action;
配置文件
pom.xml
<?xml version="1.0" encoding="UTF-8"?><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>com.iflytek</groupId><artifactId>security_demo</artifactId><version>0.0.1-SNAPSHOT</version><packaging>jar</packaging><name>security_demo</name><description>Demo project for Spring Boot</description><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>1.5.3.RELEASE</version><relativePath/> <!-- lookup parent from repository --></parent><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding><java.version>1.8</java.version></properties><repositories><repository><id>opensesame</id><name>Alibaba OpenSource Repsoitory</name><url>http://code.alibabatech.com/mvn/releases/</url><snapshots><enabled>false</enabled></snapshots></repository></repositories><dependencies><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>1.3.0</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId></dependency><dependency><groupId>org.thymeleaf.extras</groupId><artifactId>thymeleaf-extras-springsecurity4</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><scope>runtime</scope></dependency><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.0.18</version></dependency><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.31</version></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project>
springboot+mybatis配置
application.properties
spring.datasource.name = securityspring.datasource.url = jdbc:mysql://localhost:3306/security?characterEncoding=utf-8&useSSL=false&serverTimezone=UTCspring.datasource.username = rootspring.datasource.password =spring.datasource.type = com.alibaba.druid.pool.DruidDataSourcespring.datasource.driver-class-name = com.mysql.jdbc.Driverspring.datasource.filters = statspring.datasource.maxActive = 20spring.datasource.initialSize = 1spring.datasource.maxWait = 60000spring.datasource.minIdle = 1spring.datasource.timeBetweenEvictionRunsMillis = 60000spring.datasource.minEvictableIdleTimeMillis = 300000spring.datasource.validationQuery = select 'x'spring.datasource.testWhileIdle = truespring.datasource.testOnBorrow = falsespring.datasource.testOnReturn = falsespring.datasource.poolPreparedStatements = truespring.datasource.maxOpenPreparedStatements = 20server.port=8888
DruidConfig.java
import com.alibaba.druid.pool.DruidDataSource;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Value;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.context.annotation.Primary;import java.sql.SQLException;/** * Created by jjpeng on 2017/5/10. */@Configurationpublic class DruidConfig { private Logger logger = LoggerFactory.getLogger(getClass()); @Value("${spring.datasource.url}") private String dbUrl; @Value("${spring.datasource.username}") private String username; @Value("${spring.datasource.password}") private String password; @Value("${spring.datasource.driver-class-name}") private String driverClassName; @Value("${spring.datasource.initialSize}") private int initialSize; @Value("${spring.datasource.minIdle}") private int minIdle; @Value("${spring.datasource.maxActive}") private int maxActive; @Value("${spring.datasource.maxWait}") private int maxWait; @Value("${spring.datasource.timeBetweenEvictionRunsMillis}") private int timeBetweenEvictionRunsMillis; @Value("${spring.datasource.minEvictableIdleTimeMillis}") private int minEvictableIdleTimeMillis; @Value("${spring.datasource.validationQuery}") private String validationQuery; @Value("${spring.datasource.testWhileIdle}") private boolean testWhileIdle; @Value("${spring.datasource.testOnBorrow}") private boolean testOnBorrow; @Value("${spring.datasource.testOnReturn}") private boolean testOnReturn; @Value("${spring.datasource.poolPreparedStatements}") private boolean poolPreparedStatements; @Value("${spring.datasource.filters}") private String filters; @Bean @Primary public DruidDataSource druidDataSource(){ DruidDataSource datasource = new DruidDataSource(); datasource.setUrl(this.dbUrl); datasource.setUsername(username); datasource.setPassword(password); datasource.setDriverClassName(driverClassName); datasource.setInitialSize(initialSize); datasource.setMinIdle(minIdle); datasource.setMaxActive(maxActive); datasource.setMaxWait(maxWait); datasource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis); datasource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis); datasource.setValidationQuery(validationQuery); datasource.setTestWhileIdle(testWhileIdle); datasource.setTestOnBorrow(testOnBorrow); datasource.setTestOnReturn(testOnReturn); datasource.setPoolPreparedStatements(poolPreparedStatements); try { datasource.setFilters(filters); } catch (SQLException e) { logger.error("druid configuration initialization filter", e); } return datasource; }}
import org.mybatis.spring.mapper.MapperScannerConfigurer;import org.springframework.boot.autoconfigure.AutoConfigureAfter;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;/** * Created by admin on 2017/5/11. */@Configuration@AutoConfigureAfter(MybatisConfig.class)public class MapperScannerConfig { @Bean public MapperScannerConfigurer mapperScannerConfigurer() { MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer(); mapperScannerConfigurer.setSqlSessionFactoryBeanName("sqlSessionFactory"); mapperScannerConfigurer.setBasePackage("com.iflytek.dao"); return mapperScannerConfigurer; }}
MybatisConfig.java
import org.apache.ibatis.session.SqlSessionFactory;import org.mybatis.spring.SqlSessionFactoryBean;import org.mybatis.spring.SqlSessionTemplate;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.core.io.support.PathMatchingResourcePatternResolver;import org.springframework.core.io.support.ResourcePatternResolver;import org.springframework.jdbc.datasource.DataSourceTransactionManager;import org.springframework.transaction.PlatformTransactionManager;import org.springframework.transaction.annotation.EnableTransactionManagement;import org.springframework.transaction.annotation.TransactionManagementConfigurer;import javax.sql.DataSource;@Configuration@EnableTransactionManagementpublic class MybatisConfig implements TransactionManagementConfigurer{ @Autowired private DataSource dataSource; @Bean(name = "sqlSessionFactory") public SqlSessionFactory sqlSessionFactoryBean(){ SqlSessionFactoryBean bean = new SqlSessionFactoryBean(); bean.setDataSource(dataSource); bean.setTypeAliasesPackage("com.iflytek.model"); ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); try { bean.setMapperLocations(resolver.getResources("classpath:mapper/*")); return bean.getObject(); } catch (Exception e){ e.printStackTrace(); throw new RuntimeException(e); } } @Bean public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory){ return new SqlSessionTemplate(sqlSessionFactory); } @Bean @Override public PlatformTransactionManager annotationDrivenTransactionManager(){ return new DataSourceTransactionManager(dataSource); }}
Security配置
SecurityConfig.java
import com.iflytek.service.MyFilterSecurityInterceptor;import com.iflytek.service.MyUserDetailsService;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;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.builders.WebSecurity;import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;import org.springframework.security.core.userdetails.UserDetailsService;import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;/** * Created by admin on 2017/4/6. */@Configuration@EnableWebSecuritypublic class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private MyFilterSecurityInterceptor myFilterSecurityInterceptor; @Bean UserDetailsService myUserDetailsService(){ return new MyUserDetailsService(); } @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .antMatchers("/hello").permitAll() .anyRequest().authenticated() //任何请求,登录后可以访问 .and() .formLogin() .loginPage("/login") .failureUrl("/login?error") .permitAll() //登录页面用户任意访问 .and() .logout().permitAll(); //注销行为任意访问 http.addFilterBefore(myFilterSecurityInterceptor, FilterSecurityInterceptor.class).csrf().disable();; } @Override public void configure(WebSecurity web) throws Exception { web.ignoring().antMatchers("/js/**", "/css/**", "/images/**", "/**/favicon.ico"); //防止拦截css,js,image文件 } @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(myUserDetailsService()); //登录验证,绑定自定义的UserDetailServiceHolder }
SpringSecurity登录验证
1.自定义类实现UserDetailsService接口机器loadUserByUserName方法;
2.SpringSecurity的authenticationProcessingFilter拦截器调用AuthenticationManager,UserDetailsService拿到用户信息后,authenticationManager对比用户名密码,如果通过了,则相当于通过了AuthenticationProcessingFilter拦截器,也就是登录验证通过。
3.登录 获取登录用户的用户权限,将用户信息和权限信息保存在SecurityContextHolder中。
myUserDetailsService.java
@Servicepublic class MyUserDetailsService implements UserDetailsService { @Autowired private UserDao userDao; @Autowired private PermissionDao permissionDao; @Override public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException { //判断用户是否存在 SYS_User u = userDao.findByAccount(s); if (u == null){ throw new UsernameNotFoundException(s+"用户名不存在"); } //根据用户获取权限 List<SYS_Permission> permissions = permissionDao.findByUserId(u.getUserID()); //定义权限集合 List<GrantedAuthority> grantedAuthorities = new ArrayList(); //添加权限到集合中 for (SYS_Permission permission: permissions){ if (permission !=null && permission.getPermissionOperation()==true) { GrantedAuthority grantedAuthority = new SimpleGrantedAuthority(permission.getPermissionAccess() + "_" + permission.getPermissionAccessValue()); grantedAuthorities.add(grantedAuthority); } } //将已登录的用户信息保存到SecurityContext org.springframework.security.core.userdetails.User user = new User(u.getAccount(),u.getPassword(),u.getStatus(),true,true, true, grantedAuthorities); return user; }}
SpringSecurity资源访问控制
访问资源url
↓
AbstractSecurityInterceptor拦截
↓
调用FilterInvocationSecurityMetadataSource的方法(资源权限关联)来获取被拦截url所需要的全部权限
↓
调用授权管理器AccessDecisionManager(访问决策)
↓
通过全局缓存SecurityContextHolder获取用户的权限信息,decide方法判断用户是否有权限访问该资源
myFilterSecurityInterceptor.java
@Servicepublic class MyFilterSecurityInterceptor extends AbstractSecurityInterceptor implements Filter { @Autowired private FilterInvocationSecurityMetadataSource securityMetadataSource; @Autowired public void setMyAccessDecisionManager(MyAccessDecisionManager myAccessDecisionManager){ super.setAccessDecisionManager(myAccessDecisionManager); } @Override public void init(FilterConfig filterConfig) throws ServletException { } //登录后,每次访问资源都通过这个拦截器拦截 @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { FilterInvocation fi = new FilterInvocation(servletRequest,servletResponse,filterChain); invoke(fi); } @Override public void destroy() { } @Override public Class<?> getSecureObjectClass() { return FilterInvocation.class; } @Override public SecurityMetadataSource obtainSecurityMetadataSource() { return this.securityMetadataSource; } public void invoke(FilterInvocation fi) throws IOException,ServletException { //fi里面有一个被拦截的url //里面调用MyInvocationSecurityMetadataSource的getAttributes(Object object)这个方法获取fi对应的所有权限 //再调用MyAccessDecisionManager的decide方法来校验用户的权限是否足够 InterceptorStatusToken token = super.beforeInvocation(fi); try{ //执行下一个拦截器 fi.getChain().doFilter(fi.getRequest(),fi.getResponse()); }finally { super.afterInvocation(token,null); } }}
myInvocationSecurityMetadataSource.java
@Servicepublic class MyInvocationSecurityMetadataSourceService implements FilterInvocationSecurityMetadataSource { @Autowired private PermissionDao permissionDao; @Autowired private MenuDao menuDao; @Autowired private ButtonDao buttonDao; private HashMap<String, Collection<ConfigAttribute>> map =null; //加载权限表中所有权限 public void loadResourceDefine(){ map = new HashMap<>(); Collection<ConfigAttribute> atts; //获取所有权限并保存 List<SYS_Permission> permissions = permissionDao.findAll(); for(SYS_Permission permission : permissions) { atts = new ArrayList<>(); ConfigAttribute cfg = new SecurityConfig(permission.getPermissionAccess() + "_" + permission.getPermissionAccessValue()); atts.add(cfg); //对应的menu或button的url if (permission.getPermissionAccess().equals("menu")){ SYS_Menu sys_menu = menuDao.findById(permission.getPermissionAccessValue()); map.put(sys_menu.getUrl(),atts); }else if (permission.getPermissionAccess().equals("button")){ SYS_Button sys_button = buttonDao.findById(permission.getPermissionAccessValue()); map.put(sys_button.getUrl(),atts); } } } //此方法是为了判定用户请求是否在权限表中,如果在权限表中,则返回给 decide 方法,用来判定用户是否有此权限。如果不在权限表中则放行。 @Override public Collection<ConfigAttribute> getAttributes(Object o) throws IllegalArgumentException { if(map ==null) loadResourceDefine(); //object 中包含用户请求的request 信息 HttpServletRequest request = ((FilterInvocation) o).getHttpRequest(); AntPathRequestMatcher matcher; String resUrl; Iterator<String> ite = map.keySet().iterator(); while (ite.hasNext()){ resUrl = ite.next(); matcher = new AntPathRequestMatcher(resUrl); if(matcher.matches(request)) { return map.get(resUrl); } } return null; } @Override public Collection<ConfigAttribute> getAllConfigAttributes() { return null; } @Override public boolean supports(Class<?> aClass) { return true; }}
@Servicepublic class MyAccessDecisionManager implements AccessDecisionManager { // decide 方法是判定是否拥有权限的决策方法, //authentication 是UserDetailService中循环添加到 GrantedAuthority 对象中的权限信息集合. //object 包含客户端发起的请求的requset信息,可转换为 HttpServletRequest request = ((FilterInvocation) object).getHttpRequest(); //configAttributes 为MyInvocationSecurityMetadataSource的getAttributes(Object object)这个方法返回的结果,此方法是为了判定用户请求的url 是否在权限表中,如果在权限表中,则返回给 decide 方法,用来判定用户是否有此权限。如果不在权限表中则放行。 @Override public void decide(Authentication authentication, Object o, Collection<ConfigAttribute> collection) throws AccessDeniedException, InsufficientAuthenticationException { if (null == collection || collection.size()<=0){ return; } ConfigAttribute c; String needRole; Iterator<ConfigAttribute> ite = collection.iterator(); while (ite.hasNext()){ c = ite.next(); needRole = c.getAttribute(); for (GrantedAuthority ga : authentication.getAuthorities()){ if (needRole.trim().equals(ga.getAuthority())){ return; } } } throw new AccessDeniedException("no right"); } @Override public boolean supports(ConfigAttribute configAttribute) { return true; } @Override public boolean supports(Class<?> aClass) { return true; }}
- springboot+springSecurity+mybatis实现权限管理
- springboot+mybatis+SpringSecurity 实现用户角色数据库管理(一)
- springboot+mybatis+SpringSecurity 实现用户角色数据库管理(一)
- SpringBoot+SpringSecurity实现访问权限控制案例
- SpringBoot中使用Springsecurity实现权限控制
- springBoot+mybatis+springsecurity整合!
- springBoot+springSecurity 数据库动态管理用户、角色、权限(二)
- springBoot+springSecurity 动态管理Restful风格权限(三)
- springBoot+springSecurity 数据库动态管理用户、角色、权限(二)
- springBoot+springSecurity 动态管理Restful风格权限(三)
- SpringSecurity菜单权限管理
- SpringSecurity权限管理
- SpringBoot+SpringSecurity+thymeleaf 代码实现
- SSM整合SpringSecurity实现权限管理实例 javaconfig配置方式
- SSM整合SpringSecurity实现权限管理实例 javaconfig配置方式
- SpringBoot+SpringSecurity+JWT实RESTfulAPI权限控制
- springboot+shiro+mybatis实现角色权限控制
- SpringBoot整合mybatis、shiro、redis实现基于数据库的细粒度动态权限管理系统实例
- 挨踢三年
- Redis 三种启动设置
- Java设计模式-工厂模式(简单工厂+工厂方法)
- HDU1394
- oracle sql日期比较:
- springboot+springSecurity+mybatis实现权限管理
- 类似锚点链接跳转的jq代码
- SVN 服务端 配置搭建说明
- @media响应式媒介尺寸
- sklearn-加载数据
- Oracle Database 11g Release 2 RAC On Linux Using NFS
- 用hibernate的xml配置来建索引
- u-boot第一阶段分析(二)
- PHP的线程安全与非线程(NTS)安全版本的区别