SpringSecurity配置及注解说明

一、配置准备

1、引入相关pom.xml

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
            <version>2.0.4.RELEASE</version>
        </dependency>

2、实现UserDetailsService,自定义赋予角色权限

//1、实现UserDetailsService接口
@Service("userDetailsService")
public class MyUserDetailsService implements UserDetailsService {
    //实现了mybatis-plus的BaseMapper
    @Autowired
    UsersMapper usersMapper;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        //2、在其中实现方法中写入用户的验证逻辑
        //权限不能为空,一般是从数据库中读
        //当用通过角色判断是否可以访问该页面时则需要给角色的名前+‘ROLE_’
        List<GrantedAuthority> auths = AuthorityUtils.commaSeparatedStringToAuthorityList("admin2,admin,manager,ROLE_admin");
		//Users是自定义的实体类
        QueryWrapper<Users> wrapper = new QueryWrapper<>();
        //条件
        wrapper.eq("username",username);
        //从数据库中查询用户
        Users users = usersMapper.selectOne(wrapper);

        if(users == null){
            throw new UsernameNotFoundException("用户名未找到");
        }

        return new User(users.getUsername(),new BCryptPasswordEncoder().encode(users.getPassword()),auths);
    }
}

3、SpringSecurity基础配置

@Configuration
@ComponentScan("com.security.securitydemo.entity")
public class SecurityConfigTest extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserDetailsService userDetailsService;

    //1、配置数据源
    @Autowired
    private DataSource dataSource;
    //配置PersistentTokenRepository,该类用于配置token数据的处理方式
    //1、JdbcTokenRepositoryImpl 将token数据持久化(通过数据保存token)
    //2、InMemoryTokenRepositoryImpl 将token数据存在内存中
    @Bean
    public PersistentTokenRepository persistentTokenRepository(){
        JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl();
        //配置数据源
        jdbcTokenRepository.setDataSource(dataSource);
        //自动生成存储token的表
        //jdbcTokenRepository.setCreateTableOnStartup(true);
        return jdbcTokenRepository;
    }

    public void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(encoder());
    }
     /**
     * 配置页面访问权限及登录退出页面跳转,可根据自己的情况进行配置
     * @param httpSecurity
     * @throws Exception
     */
    public void configure(HttpSecurity httpSecurity) throws Exception {
//        httpSecurity.exceptionHandling().accessDeniedPage("/403");   /* 配置没有权限访问条状自定义页面 */
        //用户登录
        httpSecurity.formLogin()    /* 自定义自己编写的登录界面 */
                .loginPage("/login")   /* 登录页面设置 */
                .loginProcessingUrl("/user/login")  /* 登录访问路径 */
                .defaultSuccessUrl("/success")    /* 登陆成功后跳转路径 */
                .failureForwardUrl("/fail").permitAll()     /* 登陆失败跳转页面 */
                //权限设置
                .and().authorizeRequests()  /* 指定哪些url可以访问,那些不能访问 */
                .antMatchers("/test/index","/user/login").permitAll()    /* 设置那些路径不需要认证可以访问 */
                .antMatchers("/test/hello").hasAnyRole("admin")   /* 跟具已有角色判断是否可以访问这个页面 */
//                .antMatchers("/test/hello").hasRole("manager")     /* 跟具已有角色判断是否可以访问这个页面 */
//                .antMatchers("/test/hello").hasAnyAuthority("admin","manager") /* 只要有拥有其中一个权限即可访问这个页面 */
//                .antMatchers("/test/hello").hasAuthority("admin")    /* 当前用户登录只有具有admin权限才可以访问这个路径 */
                .anyRequest().authenticated()   /* 所有请求都可以访问 */
                //token配置
                .and().rememberMe().tokenRepository(persistentTokenRepository())    /* 2、设置PersistentTokenRepository */
                .tokenValiditySeconds(60)   /* 设置有效时长,单位秒 */
                .userDetailsService(userDetailsService);
                //.and().csrf().disable();     /* 关闭csrf防护 */
        //用户注销
        httpSecurity.logout()
                .logoutUrl("/logout")   /* 注销访问路劲 */
                .logoutSuccessUrl("/test/index").permitAll();   /* 注销成功跳转路径 */

    }
    
    @Bean
    public PasswordEncoder encoder(){
        return new BCryptPasswordEncoder();
    }
}

4、写好自己的登录页面及登录接口

@Controller
public class LoginController {
    @RequestMapping("/login")
    public String login(){
        return "login";
    }
    @RequestMapping("/success")
    public String success(){
        return "success";
    }
    @RequestMapping("/fail")
    public String fail(){
        return "fail";
    }
    @RequestMapping("/logout")
    public String logout(){
        return "login";
    }
}

5、写好用于测试的接口

@Controller
@RequestMapping("/test")
@EnableGlobalMethodSecurity(securedEnabled=true,prePostEnabled=true,jsr250Enabled = true)        /* 开启security注解 */
public class TestController {
    /**
     * @Secured 验证是否有其中一个角色,有才能调用该方法
     * @return
     */
    @Secured({"ROLE_manage","ROLE_admin"})  /* 只要拥有manage或admin其中一个角色就可以使用这个方法 */
    @RequestMapping("testSecured")
    @ResponseBody
    public String testSecured(){
        System.out.println("testSecured.....");
        return "testSecured ok";
    }

    /**
     * @RolesAllowed 验证是否有其中角色
     * 该注解需要开启jsr250Enabled
     * @return
     */
    @RolesAllowed({"ROLE_manage","ROLE_admin"})
    @RequestMapping("testRolesAllowed")
    @ResponseBody
    public String testRolesAllowed() {
        System.out.println("testRolesAllowed.....");
        return "testRolesAllowed ok";
    }

    /**
     * @PreAuthorize 在方法执行前进行权限验证
     * 在其中还可以使用其他的验证防范例如hasRole等
     * 这里是验证当前用户是否有admin权限
     * @return
     */
    @RequestMapping("testPreAuthorize")
    @ResponseBody
    @PreAuthorize("hasAnyAuthority('admin')")   /* 在方法调用之前验证是否有admin权限,没有则无法调用该方法 */
    public String testPreAuthorize(){
        System.out.println("PreAuthorize......");
        return "PreAuthorize ok";
    }

    /**
     * @PostAuthorize 在方法执行后再进行权限验证
     * 可以使用内置的表达式returnObject表示方法的返回值
     * @return
     */
    @PostAuthorize("returnObject.equals('PostAuthorize ok')")   /* 在方法执行后再进行权限验证,适合验证带有返回值的权限 */
    @RequestMapping("testPostAuthorize")
    @ResponseBody
    public String testPostAuthorize(){
        System.out.println("PostAuthorize......");
        return "PostAuthorize ok";
    }

    /**
     * @PostFilter 过滤返回的结果
     * 这里指的是只返回username为zhangsan的内容
     * @return
     */
    @PreAuthorize("hasAnyAuthority('admin')")
    @PostFilter("filterObject.username == 'zhansan'")    /* 如果有权限满足条件则过滤响应结果 */
    @ResponseBody
    @RequestMapping("testPostFilter")
    public List<Users> testPostFilter(){
        List<Users> list = new ArrayList<>();
        list.add(new Users(1,"zhansan","123"));
        list.add(new Users(2,"lisi","123"));
        System.out.println(list);
        return list;    //[{"id":1,"username":"zhansan","password":"123"}]
    }

    /**
     * @PreFilter 过滤的是传进来的参数
     * 这里指传进来Users列表中Users的id>2才能被传进来
     * @param list1
     * @return
     */
    @RequestMapping("testPreFilter")
    @PreAuthorize("hasAnyAuthority('admin')")
    @PreFilter(value = "filterObject.id %2 == 0")   /* 满足条件,对于参数数据进行过滤处理 */
    @ResponseBody
    public List<Users> testPreFilter(List<Users> list1){
        List<Users> list2 = new ArrayList<>();
        list2.add(new Users(10,"十","12345"));
        list1.addAll(list2);
        return list1;
    }
}

二、注解说明

在使用springsecurity注解之前需要在类上开启springsecurity的注解

@EnableGlobalMethodSecurity(securedEnabled=true,prePostEnabled=true,jsr250Enabled = true)        /* 开启security注解 */

权限均参照以上我在MyUserDetailsService中配置的权限,及以上在接口配置的注解

List<GrantedAuthority> auths = AuthorityUtils.commaSeparatedStringToAuthorityList("admin2,admin,manager,ROLE_admin");

1、@Secured

验证是否有其中的一个角色,有才能调用该接口
注意:在使用该接口前必须在 @EnableGlobalMethodSecurity 注解中添加securedEnabled=true才能使该注解生效

@Secured({"ROLE_manage","ROLE_admin"})

演示效果
SpringSecurity配置及注解说明

2、@RolesAllowed

类似于@Secured 验证是否有其中的一个角色,有才能调用该接口
注意:该注解需要开启jsr250Enabled

@RolesAllowed({"ROLE_manage","ROLE_admin"})

演示效果
SpringSecurity配置及注解说明

3、@PreAuthorize

注意:该注解需要开启prePostEnabled=true
在方法执行前进行权限验证,主要是配合以下的验证方法对用户进行权限验证
hasRole(“manager”)、hasAnyAuthority(“admin”,“manager”)、hasAuthority(“admin”)、hasAnyRole(“admin”)

@PreAuthorize("hasAnyAuthority('admin')")

演示效果
SpringSecurity配置及注解说明

4、@PostAuthorize

注意:该注解需要开启prePostEnabled=true
在方法执行后对返回值进行权限验证
可以使用内置的表达式returnObject表示方法的返回值

以下演示返回值均是之前代码的返回值,这里的返回值是PostAuthorize ok

@PostAuthorize("returnObject.equals('PostAuthorize ok')")

演示效果
SpringSecurity配置及注解说明

@PostAuthorize("returnObject.equals('PostAuthorize no')")

演示效果(该页面为自定义的403无权限提示页面)
SpringSecurity配置及注解说明

5、@PostFilter

过滤返回的结果
filterObject是执行过滤操作的内置对象。

@PostFilter("filterObject.username == 'zhansan'") 	//这里指的是只返回username为zhangsan的内容

演示效果
返回全部内容如下所示

    public List<Users> testPostFilter(){
        List<Users> list = new ArrayList<>();
        list.add(new Users(1,"zhansan","123"));
        list.add(new Users(2,"lisi","123"));
        System.out.println(list);
        return list;    //[{"id":1,"username":"zhansan","password":"123"}]
    }

SpringSecurity配置及注解说明

6、@PreFilter

过滤的是传进来的参数
filterObject是执行过滤操作的内置对象。

后续补充。。。。。

上一篇:win7下用c#开发windows服务


下一篇:*信息公开