springboot+mybatis+spring security

来源:互联网 发布:海尔软件收入 编辑:程序博客网 时间:2024/05/16 12:21

1、不啰嗦,直接上干货
首先新建项目springboot-security导入需要的maven坐标

 <parent>        <groupId>org.springframework.boot</groupId>        <artifactId>spring-boot-starter-parent</artifactId>        <version>1.3.0.RELEASE</version>    </parent>    <properties>        <start-class>com.us.example.Application</start-class>        <maven.compiler.target>1.8</maven.compiler.target>        <maven.compiler.source>1.8</maven.compiler.source>        <mybatis.version>3.2.7</mybatis.version>        <mybatis-spring.version>1.2.2</mybatis-spring.version>    </properties>    <dependencies>        <!--springboot-->        <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>        <!--db-->        <dependency>            <groupId>mysql</groupId>            <artifactId>mysql-connector-java</artifactId>            <version>6.0.5</version>        </dependency>        <dependency>            <groupId>com.mchange</groupId>            <artifactId>c3p0</artifactId>            <version>0.9.5.2</version>            <exclusions>                <exclusion>                    <groupId>commons-logging</groupId>                    <artifactId>commons-logging</artifactId>                </exclusion>            </exclusions>        </dependency>        <!--mybatis-->        <dependency>            <groupId>org.springframework</groupId>            <artifactId>spring-jdbc</artifactId>        </dependency>        <dependency>            <groupId>org.mybatis</groupId>            <artifactId>mybatis</artifactId>            <version>${mybatis.version}</version>        </dependency>        <dependency>            <groupId>org.mybatis</groupId>            <artifactId>mybatis-spring</artifactId>            <version>${mybatis-spring.version}</version>        </dependency>    </dependencies>    <build>        <plugins>            <!--&lt;!&ndash;打依赖包&ndash;&gt;-->            <plugin>                <groupId>org.apache.maven.plugins</groupId>                <artifactId>maven-shade-plugin</artifactId>                <version>2.3</version>                <executions>                    <execution>                        <phase>package</phase>                        <goals>                            <goal>shade</goal>                        </goals>                    </execution>                </executions>            </plugin>        </plugins>    </build>

2、自定义配置FilterSecurityInterceptor,而这个拦截器需要注入自己定义的SecruityMetadataService
3、由2可知新建MySecruityMetadataService,这个类需要实现FilterInvocationSecurityMetadataSource接口,在这个类中有主要的三部分:第一:加载所有的权限列表;第二:取到当前访问的路径;第三:拿到的路径为访问路径的权限列表

@Servicepublic class MySecruityMetadataService  implements        FilterInvocationSecurityMetadataSource {    @Autowired    private PermissionDao permissionDao;    private HashMap<String, Collection<ConfigAttribute>> map =null;    /**     * 加载资源,初始化资源变量     */    public void loadResourceDefine(){        map = new HashMap<>();        Collection<ConfigAttribute> array;        ConfigAttribute cfg;        List<Permission> permissions = permissionDao.findAll();        for(Permission permission : permissions) {            array = new ArrayList<>();            cfg = new SecurityConfig(permission.getName());            array.add(cfg);            map.put(permission.getUrl(), array);        }    }    @Override    public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException {        if(map ==null) loadResourceDefine();        HttpServletRequest request = ((FilterInvocation) object).getHttpRequest();        AntPathRequestMatcher matcher;        String resUrl;        for(Iterator<String> iter = map.keySet().iterator(); iter.hasNext(); ) {            resUrl = iter.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<?> clazz) {        return true;    }}

4、回退到第二步,注入自己的MySecruityMetadataService,执行过滤器(调用父类,父类中会执行)

@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 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 {    //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);        }    }    @Override    public void destroy() {    }    @Override    public Class<?> getSecureObjectClass() {        return FilterInvocation.class;    }    @Override    public SecurityMetadataSource obtainSecurityMetadataSource() {        return this.securityMetadataSource;    }}

5、配置自定义的MyUserDetailsService,查询出此用户的所有访问权限

@Servicepublic class CustomUserService implements UserDetailsService { //自定义UserDetailsService 接口    @Autowired    UserDao userDao;    @Autowired    PermissionDao permissionDao;    public UserDetails loadUserByUsername(String username) {        SysUser user = userDao.findByUserName(username);        if (user != null) {            List<Permission> permissions = permissionDao.findByAdminUserId(user.getId());            List<GrantedAuthority> grantedAuthorities = new ArrayList <>();            for (Permission permission : permissions) {                if (permission != null && permission.getName()!=null) {                GrantedAuthority grantedAuthority = new SimpleGrantedAuthority(permission.getName());                grantedAuthorities.add(grantedAuthority);                }            }            return new User(user.getUsername(), user.getPassword(), grantedAuthorities);        } else {            throw new UsernameNotFoundException("admin: " + username + " do not exist!");        }    }}

6、在自定义的MyAccessDecisionManager中判断自己通过用户名查询出来的权限列表中是否包含通过访问路径查询出来的权限。

@Servicepublic class MyAccessDecisionManager implements AccessDecisionManager {    @Override    public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes) throws AccessDeniedException, InsufficientAuthenticationException {        if(null== configAttributes || configAttributes.size() <=0) {            return;        }        ConfigAttribute c;        String needRole;        for(Iterator<ConfigAttribute> iter = configAttributes.iterator(); iter.hasNext(); ) {            c = iter.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 attribute) {        return true;    }    @Override    public boolean supports(Class<?> clazz) {        return true;    }}

7、页面展示控制

         <div sec:authorize="hasRole('ROLE_ADMIN')">          <!-- 用户类型为ROLE_ADMIN 显示 -->              <p class="bg-info">恭喜您,您有 ROLE_ADMIN 权限 </p>          </div>

8、最后还需要一个配置类继承WebSecurityConfigurerAdapter,实现对请求进行过滤

@Configuration@EnableWebSecurity@EnableGlobalMethodSecurity(prePostEnabled = true) //开启方法级别的权限注解public class WebSecurityConfig extends WebSecurityConfigurerAdapter {    @Autowired    private MyFilterSecurityInterceptor myFilterSecurityInterceptor;    @Autowired    UserDetailsService customUserService;    @Override    protected void configure(AuthenticationManagerBuilder auth) throws Exception {        auth.userDetailsService(customUserService); //user Details Service验证    }    @Override    protected void configure(HttpSecurity http) throws Exception {        http.authorizeRequests()                .antMatchers("/css/**").permitAll()                .anyRequest().authenticated() //任何请求,登录后可以访问                .and()                .formLogin()                .loginPage("/login")                .defaultSuccessUrl("/")                .failureUrl("/login?error")                .permitAll() //登录页面用户任意访问                .and()                .logout().permitAll(); //注销行为任意访问        http.addFilterBefore(myFilterSecurityInterceptor, FilterSecurityInterceptor.class);    }}

8、开启方法级别的注解权限(第七配置类的@EnableGlobalMethodSecurity(prePostEnabled = true) //开启方法级别的权限注解)使用方式

  @RequestMapping("/admin")    @ResponseBody    @PreAuthorize("hasAnyRole('ROLE_ADMIN')")    public String hello(){        return "hello admin";    }

https://git.oschina.net/itheima_liang/springboot-mybatis-springsecurity.wiki.git

----------------ITteenager
原创粉丝点击