springboot整合spring-security
来源:互联网 发布:适合初中生看的编程书 编辑:程序博客网 时间:2024/05/17 18:01
前言
前几天学习了spring的权限管理框架spring-security(项目需要),然后自己搭建了一个和数据库结合的权限管理框架,具体如下
POM依赖
因为现在项目基本都用的是maven所以我就不废话了,主要的依赖如下:
<dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>1.3.1</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.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-test</artifactId> <scope>test</scope> </dependency>
具体的用户对象
我创建的对象有SRole、SysUser、SysResource,创建了5张表(用户和角色中间表和角色和资源的一张中间表,其实spring-security不管你多少张表你只要把你登陆的用户是什么角色(也可以说有什么权限),每个资源应该被那些角色(权限)所访问就行了(具体我会在下一章说到))
SRole角色:
public class SRole { private Integer id; private String name;}
SysUser角色:
public class SysUser {
private Integer id;
private String num;
private String password;
private List roles; // 所拥有的角色
}
SysResource
public class SysResource { private Integer id; private String resourcename;}
好了以上就是一些简单的创建和配置,接下来的才是重点,spring-security可以根据很多方式来实现权限什么内存啦,配置啦,数据库啦,修改源码什么的(这个是真的牛逼),这里我只说数据库.
配置登陆和退出的config
在认证的时候肯定是需要登陆页面、退出页面、那些请求拦截,那些请求不拦截等等,这些是通过继承WebSecurityConfigurerAdapter来实现的我的代码如下所示:
import org.springframework.beans.factory.annotation.Autowired;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.configuration.EnableWebSecurity;import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;import com.example.service.security.CustomUserDetailsService;@Configuration@EnableWebSecuritypublic class WebSecurityConfig extends WebSecurityConfigurerAdapter{ @Autowired private CustomUserDetailsService cds; @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(cds); } @Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .antMatchers("/","/index").permitAll() //访问 '/' 和 '/index' 无需登录认证权限 .anyRequest().authenticated()//其他所有资源都需要认证,登陆后访问 .and() .formLogin() .loginPage("/login") //指定登陆页面是login .defaultSuccessUrl("/index") .permitAll() .and() .logout() .logoutUrl("/loginout") .permitAll(); }}
这时候你脑子里肯定有一个疑问:WIF?这配置什么登陆啊登出啊我懂了那么一丢丢,这个飞来的CustomUserDetailsService 是干啥的?我在我写的
CustomUserDetailsService
嗯,是正确的时间贴出来CustomUserDetailsService的类了
import java.util.ArrayList;import java.util.List;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.security.core.GrantedAuthority;import org.springframework.security.core.authority.SimpleGrantedAuthority;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.example.dao.SysUserDao;import com.example.domain.SRole;import com.example.domain.SysUser;@Servicepublic class CustomUserDetailsService implements UserDetailsService{ @Autowired private SysUserDao sud; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { SysUser user = sud.findByName(username); if(user == null) throw new UsernameNotFoundException(username); List<GrantedAuthority> authorities = new ArrayList<>(); for(SRole role : user.getRoles()) { authorities.add(new SimpleGrantedAuthority(role.getName())); } return new org.springframework.security.core.userdetails.User(user.getNum(),user.getPassword(),authorities); }}
OK接下来说说我们还需要什么类吧,spring-security是通过拦截器来实现权限啊什么资源的保护的,那正常步骤我们需要自定义一个拦截器,嘿嘿。。。。有没有那么一点点颤抖的感觉。直接上代码吧骚年。。
Filter
import java.io.IOException;
import javax.annotation.PostConstruct;
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.authentication.AuthenticationManager;
import org.springframework.security.web.FilterInvocation;
import org.springframework.stereotype.Service;
import com.example.mysecurity.MyAccessDecisionManager;
import com.example.mysecurity.MyInvocationSecurityMetadataSource;
@Service
public class MySecurityFilter extends AbstractSecurityInterceptor implements Filter{
@Autowiredprivate MyInvocationSecurityMetadataSource mySecurityMetadataSource;@Autowiredprivate MyAccessDecisionManager myAccessDecisionManager;@Autowiredprivate AuthenticationManager authenticationManager;@PostConstruct public void init(){ super.setAuthenticationManager(authenticationManager); super.setAccessDecisionManager(myAccessDecisionManager); } @Overridepublic void destroy() { System.out.println("filter===========================end"); }@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { FilterInvocation fi = new FilterInvocation( request, response, chain ); invoke(fi); }public void invoke( FilterInvocation fi ) throws IOException, ServletException{ System.out.println("filter.........................."); InterceptorStatusToken token = super.beforeInvocation(fi); try{ fi.getChain().doFilter(fi.getRequest(), fi.getResponse()); }finally{ super.afterInvocation(token, null); } } @Overridepublic void init(FilterConfig arg0) throws ServletException { System.out.println("filter==========================="); }@Overridepublic Class<?> getSecureObjectClass() { return FilterInvocation.class;}@Overridepublic SecurityMetadataSource obtainSecurityMetadataSource() { return this.mySecurityMetadataSource;}
}
OK不知道你看到这段代码的时候有没有蒙逼,但是我照这网上其他例子配的时候是真的蒙逼…….完全不知道MyAccessDecisionManager,MyInvocationSecurityMetadataSource是做什么的配它们有什么用。那个我先把这两个类的代码给大家贴出来,慢慢say say.
import java.util.Collection;import java.util.Iterator;import org.springframework.security.access.AccessDecisionManager;import org.springframework.security.access.AccessDeniedException;import org.springframework.security.access.ConfigAttribute;import org.springframework.security.access.SecurityConfig;import org.springframework.security.authentication.InsufficientAuthenticationException;import org.springframework.security.core.Authentication;import org.springframework.security.core.GrantedAuthority;import org.springframework.security.core.userdetails.UserDetails;import org.springframework.stereotype.Service;@Servicepublic class MyAccessDecisionManager implements AccessDecisionManager{ /** * 验证用户是否有权访问权限 * SecurityContextHolder存储当前与应用程序交互的委托人的细节,Spring Security使用一个Authentication来表示这个信息 */ @Override public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes) throws AccessDeniedException, InsufficientAuthenticationException { /*允许访问没有设置权限的资源*/ if(configAttributes == null) { return; } //configAttributes是从MyInvocationSecurityMetadataSource的getAttributes方法得到的url所有权限拥有者 Iterator<ConfigAttribute> ite = configAttributes.iterator(); while( ite.hasNext()){ ConfigAttribute ca = ite.next(); String needRole = ((SecurityConfig)ca).getAttribute(); //ga 为用户所被赋予的权限。 needRole 为访问相应的资源应该具有的权限。</span> for( GrantedAuthority ga: authentication.getAuthorities()){ //如果url所对应的角色权限中包含当前用户的角色则投赞成票 if(needRole.trim().equals(ga.getAuthority().trim())){ return; } } } System.out.println("权限不足"); throw new AccessDeniedException("权限不足"); } @Override public boolean supports(ConfigAttribute attribute) { return true; } @Override public boolean supports(Class<?> clazz) { return true; }}
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.stereotype.Service;
import com.example.dao.SResourceVODao;
import com.example.dao.SRoleVODao;
@Service
public class MyInvocationSecurityMetadataSource implements FilterInvocationSecurityMetadataSource {
private static Map<String, Collection<ConfigAttribute>> resourceMap = new HashMap<String, Collection<ConfigAttribute>>();@Autowiredprivate SResourceVODao sResourceVODao; @Autowiredprivate SRoleVODao sRoleVODao;/** * 被@PostConstruct修饰的方法会在服务器加载Servle的时候运行, * 并且只会被服务器执行一次。 * PostConstruct在构造函数之后执行,init()方法之前执行 */@PostConstruct private void loadResourceDefine() { //List<Map<String,String>> list =sRoleVODao.findAll(); List<String> roles = sRoleVODao.findAll(); //得到所有角色 resourceMap = new HashMap<String, Collection<ConfigAttribute>>(); for (String auth : roles) { ConfigAttribute ca = new SecurityConfig(auth); List<String> resources = sResourceVODao.findByRoleName(auth); //通过角色查找到所对应的资源 for(String resource : resources) { //以资源为key将角色放到集合里面 if (resourceMap.containsKey(resource)) { Collection<ConfigAttribute> value = resourceMap.get(resource); value.add(ca); } else { Collection<ConfigAttribute> atts = new ArrayList<ConfigAttribute>(); atts.add(ca); resourceMap.put(resource, atts); } } }}//得到url对应的所有权限拥有者@Overridepublic Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException { FilterInvocation filterInvocation = (FilterInvocation) object; if (resourceMap == null) { loadResourceDefine(); } Iterator<String> ite = resourceMap.keySet().iterator(); while (ite.hasNext()) { String resURL = ite.next(); RequestMatcher requestMatcher = new AntPathRequestMatcher(resURL); if(requestMatcher.matches(filterInvocation.getHttpRequest())) { return resourceMap.get(resURL); } } return null;}@Overridepublic Collection<ConfigAttribute> getAllConfigAttributes() { return new ArrayList<ConfigAttribute>(); }@Overridepublic boolean supports(Class<?> clazz) { return true;}
}
OK配上这些东西剩下的就只剩下建数据库表了,大家自己动动手吧,我赖给大家讲解一下他们之间的关系(本来还想画图呢但是我的word不能用了)。
MysecurityFilter过滤器会从MyInvocationSecurityMetadataSource拿到所有资源(数据库里面的,就是那个getAttributes方法)和每个资源所对应的权限,然后MyAccessDecisionManager拿着这些资源和用户的那些资源权限进行一波对比就是那个decide()方法来判断是否授权。
结语
OK,差不多就可以使用了,至于源码什么的,嗯可能下一章会讲吧,也就只讲一点点
- springboot整合spring-security
- SpringBoot整合Spring Security和Mybatis验证
- springBoot(七)整合之整合spring Security理解
- springboot+security框架整合
- Springboot 1.5.1整合Spring security 4.2.1
- SpringBoot - Spring Security学习
- springboot+mybatis+spring security
- SpringBoot~Spring Security入门
- spring security 整合
- spring security 整合 CAS
- spring security 整合 CAS
- spring security 整合cas
- spring-security-oauth2整合
- spring-security整合CAS
- Spring Security 整合Cas
- spring boot整合security
- springboot集成spring security初探
- spring security整合spring mvc
- 写给有 NOIP考前综合征 的 oier
- Unity与游戏开发
- sdnu1468.查找整数
- caffe平台搭建~~sjtuicat 实验室倾情奉献!
- java作业2017 11 10
- springboot整合spring-security
- 算法:编写程序,根据输入的学生成绩,给出相应的等级,90~100为A
- 过滤器
- java导出excel工具类
- 5.4
- React-native PanResponder监测手势实现下拉或者上拉刷新
- react-native 使用 StackNavigator 导航器跳转页面
- Drawer侧滑
- numpy使用(argsort)