博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
使用Spring Security进行权限验证
阅读量:4091 次
发布时间:2019-05-25

本文共 7095 字,大约阅读时间需要 23 分钟。

使用 Security进行权限验证 由发表在

Security,这是一种基于Spring AOP和Servlet过滤器的安全框架。它提供全面的安全性解决方案,同时在Web请求级和方法调用级处理身份确认和授权。在Spring Framework基础上,Spring Security充分利用了依赖注入(DI,Dependency Injection)和面向切面技术。今天我们就来学习一下如何利用Spring security方便的进行权限验证。

添加依赖

首先还是先定义我们所需要的依赖:

org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-security
org.springframework.boot
spring-boot-starter-thymeleaf
org.springframework.boot
spring-boot-starter-data-jpa
org.hsqldb
hsqldb
runtime

在本次学习中,我们仍然使用作为框架,同时引入我们的核心学习库:spring-boot-starter-security。模板引擎仍然选用我们熟悉的thymeleaf。最后使用了Spring Data Jpa+ hsqldb作为数据库。

系统设计

本次学习,我们将实现一个简单的有权限验证的系统,在权限验证上,我们还可以加上一个简单的用户角色判断的验证,这样,我们就有以下几个页面:

  • 首页 所有人可访问
  • 登录页 所有人可访问
  • 普通页 登录后的用户都可访问
  • 管理页 管理员可访问
  • 无权限提醒页 当一个用户访问了其没有权限的页面,需要有一个页面来对其进行提醒

页面确定后,我们来看看用户表需要哪些字段。为了简化处理,我们的用户表只需要用户名、密码以及一个角色字段来确定其身份即可。

这样,我们的简单系统设计就出来了,为了加深印象,我们先不管权限验证相关代码,我们先来实现整个简单的系统吧。

系统实现

数据访问层

首先我们需要一个数据层以及业务层为我们的业务逻辑提供支持,由于我们没有业务逻辑,业务逻辑层就省去了,只需要利用来实现一个简单数据访问层即可。

首先来定义一个User对象,设置用户名、密码、角色三个字段:

@Entitypublic class User {    @Enumerated(EnumType.STRING)    private ROLE role;    @Id    private String username;    private String password;    ...}

然后定义UserRepository:

public interface UserRepository extends JpaRepository
{ User findByUsername(String username);}

这样,数据访问层就实现好了。

展现层

在展现层,我们需要提供中的所有页面。Controller代码如下:

@Controllerpublic class HomeController {    @RequestMapping(value = {"", "/home"}, method=RequestMethod.GET)    public String home(){        return "home";    }    @RequestMapping(value = "/helloadmin", method=RequestMethod.GET)    public String helloAdmin(){        return "helloAdmin";    }    @RequestMapping(value = "/hellouser", method=RequestMethod.GET)    public String helloUser(){        return "helloUser";    }    @RequestMapping(value = "/login", method=RequestMethod.GET)    public String login(){        return "login";    }    @RequestMapping("/403")    public String forbidden(){        return "403";    }}

注:其中返回的页面在src/main/resources/templates下,都是最简单的HTML页面,这里不在赘述。

大家可以看到,最后一个403页面实际上应该是当用户访问了没有权限的页面后显示的页面,因此在这里我们需要设置:当发现请求的返回码是403时,需要交给'/403'进行处理。

@Configurationpublic class ErrorPageConfig {    @Bean    public EmbeddedServletContainerCustomizer embeddedServletContainerCustomizer(){        return new MyCustomizer();    }    private static class MyCustomizer implements EmbeddedServletContainerCustomizer {        @Override        public void customize(ConfigurableEmbeddedServletContainer container) {            container.addErrorPages(new ErrorPage(HttpStatus.FORBIDDEN, "/403"));        }    }}

这里我们利用了Spring自带的EmbeddedServletContainerCustomizer进行设置。当Spring发现有类型为EmbeddedServletContainerCustomizer注册进来,便会调用EmbeddedServletContainerCustomizer的customize方法,此时,我们可以对整个Container进行设置,这里,我们添加了对于返回值为HttpStatus.FORBIDDEN的请求,将其交给/403进行处理。

启动程序

当然,我们还需要添加一个系统的启动函数,这个大家都应该很熟悉了,没有用过Spring Boot的同学可以参考教材。

@SpringBootApplicationpublic class App {    public static void main( String[] args ){        SpringApplication.run(App.class, args);    }}

初始化数据

最后,让我们准备一些测试数据:

@Servicepublic class DataInit {    @Autowired UserRepository userRepository;    @PostConstruct    public void dataInit(){        User admin = new User();        admin.setPassword("admin");        admin.setUsername("admin");        admin.setRole(User.ROLE.admin);        userRepository.save(admin);        User user = new User();        user.setPassword("user");        user.setUsername("user");        user.setRole(User.ROLE.user);        userRepository.save(user);    }}

现在,一切准备就绪,进入根目录,运行mvn spring-boot:run,访问以下网页即可:

添加权限验证

上节内容我们搭建了一个简单的网页应用,但是其中完全没有任何登录、登出、权限验证等等的处理,只能保证每个页面的简单访问。接下来我们就来用Spring Security添加这些功能。

添加Spring Security配置

我们首先使用Spring Security帮我们做登录、登出的处理,以及当用户未登录时只能访问以及两个页面。

从数据库中获取用户信息的操作是必不可少的,我们首先来实现UserDetailsService,这个接口需要我们实现一个方法:loadUserByUsername。即通过用户名加载与该用户的用户名、密码以及权限相关的信息。

public class CustomUserDetailsService implements UserDetailsService {    @Autowired UserRepository userRepository;    @Override    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {        User user = userRepository.findByUsername(username);        if(user == null){            throw new UsernameNotFoundException("not found");        }        List
authorities = new ArrayList<>(); authorities.add(new SimpleGrantedAuthority(user.getRole().name())); System.err.println("username is " + username + ", " + user.getRole().name()); return new org.springframework.security.core.userdetails.User(user.getUsername(), user.getPassword(), authorities); }}

然后我们添加一个SecurityConfig类来对Security进行配置,使AuthenticationManager使用我们的CustomUserDetailsService来获取用户信息:

@Configuration@EnableWebMvcSecurity@EnableGlobalMethodSecurity(prePostEnabled = true)public class SecurityConfig extends WebSecurityConfigurerAdapter {    @Override    @Bean    public UserDetailsService userDetailsService() {        return new CustomUserDetailsService();    }    @Override      protected void configure(AuthenticationManagerBuilder auth)              throws Exception {          auth.userDetailsService(userDetailsService());      }      @Override    protected void configure(HttpSecurity http) throws Exception {        http            .authorizeRequests()                .antMatchers("/", "/home").permitAll()                .anyRequest().authenticated()                .and()            .formLogin()                .loginPage("/login")                .defaultSuccessUrl("/helloadmin")                .permitAll()                .and()            .logout()                .permitAll();    }}

我们可以看到,SecurityConfig上添加了@EnableWebMvcSecurity标注,使得Spring Security提供并且支持了Spring MVC的集成。

同时,SecurityConfig还继承了WebSecurityConfigurerAdapter类,并覆盖了其中的几个方法:

  • userDetailsService()将我们自定义的CustomUserDetailsService实例化并添加进security的上下文当中
  • configure(AuthenticationManagerBuilder auth) 在该方法中,我们使AuthenticationManager使用CustomUserDetailsService作为其UserDetailsService实例。
  • configure(HttpSecurity http) 对URL进行权限配置,使得"/", "/home"不需要登录就可以访问,其他需要登录。登录的地址是'/login',当登录成功后将跳转到/helloadmin页面,并且登录、登出页面都是不需要登录就可以访问的。

这时候重启我们的应用,再次访问,你会发现网页会自动跳转到登录页面,同时,我们的登录、登出功能已经实现好了。

实现一个UserDetailsService,再对Spring Security进行配置,这样,登录、登出以及登录的验证功能就可以实现啦,怎么样,是不是特别的简单。

添加角色验证

之前系统设计时,我们将用户分成了管理员与普通用户,那么,如何将这两类用户访问的页面分开,使得普通用户看不见管理员相关的页面呢?很简单,我们可以通过两行标注来实现这个功能,修改HomeController

@RequestMapping(value = "/helloadmin", method=RequestMethod.GET)@PreAuthorize("hasAnyRole('admin')")public String helloAdmin(){    return "helloAdmin";}@RequestMapping(value = "/hellouser", method=RequestMethod.GET)@PreAuthorize("hasAnyRole('admin', 'user')")public String helloUser(){    return "helloUser";}

修改helloAdminhelloUser方法,添加@PreAuthorize标注,当我们访问这两个URL的时候,Spring Security会帮我们验证当前用户是否有权限访问该地址。

现在重新启动服务,用user账号登陆,访问'',怎么样,是不是看见403页面啦。添加角色控制,就是这么简单。

更多文章请访问

你可能感兴趣的文章
图形学 图形渲染管线
查看>>
DirectX11 计时和动画
查看>>
DirectX11 光照与材质的相互作用
查看>>
DirectX11 法线向量
查看>>
DirectX11 兰伯特余弦定理(Lambert)
查看>>
DirectX11 漫反射光
查看>>
DirectX11 环境光
查看>>
DirectX11 镜面光
查看>>
DirectX11 三种光照组成对比
查看>>
DirectX11 指定材质
查看>>
DirectX11 平行光
查看>>
DirectX11 点光
查看>>
DirectX11 聚光灯
查看>>
DirectX11 HLSL打包(packing)格式和“pad”变量的必要性
查看>>
DirectX11 光照演示示例Demo
查看>>
漫谈一下前端的可视化技术
查看>>
VUe+webpack构建单页router应用(一)
查看>>
Vue+webpack构建单页router应用(二)
查看>>
从头开始讲Node.js——异步与事件驱动
查看>>
Node.js-模块和包
查看>>