Spring-Security权限实例

基于springBoot项目

引入依赖配置文件

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

快速上手

不连接数据库

1.创建用户实体类

@Data
@AllArgsConstructor
@NoArgsConstructor
public class UserTest {
    private String username;
    private String password;
}

2.Controller层(测试权限)

@RestController
@RequestMapping("/test")
public class MyController {
    @GetMapping
    public String test01() {
        return "hello security!!!";
    }
}
@RestController
public class SuccessController {
    @GetMapping("success")
    public String test02() {
        return "success";
    }
    @Secured({"ROLE_ADMIN"})
    @RequestMapping("testSecured")
    public String test03() {
        return  "testSecured";
    }
    @PreAuthorize("hasAnyAuthority('testpath')")
    @RequestMapping("")
    public String test04() {
        return "testSecured02";
    }
}

3.security配置文件 

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
//        配置登录的form表单
//        路径前面必须加/
        http.formLogin()
                .loginPage("/login.html")
                .loginProcessingUrl("/userlogin")
                .usernameParameter("myname")
                .passwordParameter("mypwd")
                .defaultSuccessUrl("/success");
        http.authorizeRequests().antMatchers("/login.html","/userlogin","/").permitAll();
        // 其他的路径  都需要认证
        http.authorizeRequests().anyRequest().authenticated();
//          权限不允许的时候
        http.exceptionHandling().accessDeniedPage("/403.html");
        //  csrf  方便html 文件  能够通过
        http.csrf().disable();
    }

    @Resource
    private UserDetailsService userDetailsService;

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

    //    自定义用户的信息
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(getPassword());
    }
}

4.service逻辑代码

@Service
public class MyUserDetailService implements UserDetailsService {
    

//    根据用户的名字 加载用户的信息
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
//        username 代表前端传递过来的名字
        BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
        String encode = passwordEncoder.encode("root");
        UserTest userTest = new UserTest("root", encode);
        if(username.equals(userTest.getUsername())) {
            List<SimpleGrantedAuthority> authorities = new ArrayList<>();
//            authorities 代表所有资源的信息
            authorities.add(new SimpleGrantedAuthority("testpath"));
            authorities.add(new SimpleGrantedAuthority("ROLE_USER"));
            return new User(username,encode,authorities);
        }
        return null;
    }
}

连接数据库(权限实例)

sql文件顶部资源下载

1.引入相关依赖

        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
            <scope>runtime</scope>
        </dependency>
        <!-- mp-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.5.3</version>
        </dependency>

        <!-- 自动生成-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-generator</artifactId>
            <version>3.5.3</version>
        </dependency>

        <!-- 模板-->
        <dependency>
            <groupId>org.apache.velocity</groupId>
            <artifactId>velocity-engine-core</artifactId>
            <version>2.3</version>
        </dependency>

        <dependency>
            <groupId>org.freemarker</groupId>
            <artifactId>freemarker</artifactId>
        </dependency>

2.通过mybatis-plus快速生成代码

public class MyTest {
    public static void main(String[] args) {
        FastAutoGenerator.create("jdbc:mysql:///test01?useSSL=false","root","root")
                // 全局配置
                .globalConfig((scanner, builder) -> builder
                        .author("hp")
                        .outputDir("D:\\Idea-spring-security\\demo01\\src\\main\\java")
                )
                // 包配置
                .packageConfig(
                        (scanner, builder) ->
                                builder
                                        .parent("com.security")
                                        .pathInfo(Collections.singletonMap(OutputFile.xml, "D:\\Idea-spring-security\\demo01\\src\\main\\resources\\mapper")))
                // 策略配置
                .strategyConfig((scanner, builder) -> builder.addInclude(getTables(scanner.apply("请输入表名,多个英文逗号分隔?所有输入 all")))
                        .controllerBuilder().enableRestStyle().enableHyphenStyle()
                        .entityBuilder().enableLombok().addTableFills(
                                new Column("create_time", FieldFill.INSERT)
                        ).build())
                /*
                    模板引擎配置,默认 Velocity 可选模板引擎 Beetl 或 Freemarker
                   .templateEngine(new BeetlTemplateEngine())
                   .templateEngine(new FreemarkerTemplateEngine())
                 */
                .execute();


// 处理 all 情况

    }

    protected static List<String> getTables(String tables) {
        return "all".equals(tables) ? Collections.emptyList() : Arrays.asList(tables.split(","));
    }
}

3.application 文件

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql:///test01?serverTimezone=UTC
    password: root
    username: root
  jackson:
    date-format: yyyy-MM-dd HH:mm:ss
    time-zone: GMT+8
    serialization:
      write-date-keys-as-timestamps: false
  mvc:
    pathmatch:
      matching-strategy: ant_path_matcher

mybatis-plus:
  configuration:
    map-underscore-to-camel-case: true
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  mapper-locations: classpath:/mapper/*.xml
  global-config:
    db-config:
      logic-not-delete-value: 1
      logic-delete-value: 0
  type-aliases-package: com.security.entity


4.TabMenuMapper.xml文件

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.security.mapper.TabMenuMapper">
    <select id="selectCodeByRids" resultType="TabMenu">
        select *
        from tab_menu
        where id in
        (
        select mid
        from tab_role_menu
        where rid in
        <foreach collection="list" item="rid" open="(" close=")" separator=",">
            #{rid}
        </foreach>
        )
    </select>
</mapper>

5.TabMenuMapper

public interface TabMenuMapper extends BaseMapper<TabMenu> {
    List<TabMenu> selectCodeByRids(List<Integer> rids);
}

6.修改service文件

@Service
public class MyUserDetailService implements UserDetailsService {
    @Resource
    private TabUserMapper userMapper;
    @Resource
    private TabUserRoleMapper userRoleMapper;
    @Resource
    private TabRoleMapper roleMapper;
    @Resource
    private TabMenuMapper menuMapper;

//    根据用户的名字 加载用户的信息
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
//        username 代表前端传递过来的名字
//        根据名字去数据库查询一下有没有这个用户的信息
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.eq("username",username);
        TabUser tabUser = userMapper.selectOne(queryWrapper);
        if(tabUser != null) {
//            有值 查询用户对应的角色的id
            QueryWrapper queryWrapper1 = new QueryWrapper();
            queryWrapper1.eq("uid",tabUser.getId());
            List<TabUserRole> tabUserRoles = userRoleMapper.selectList(queryWrapper1);
            List<Integer> rids = tabUserRoles.stream().map(tabUserRole -> tabUserRole.getRid()).collect(Collectors.toList());
//            根据角色的id 查询rcode
            List<TabRole> tabRoles = roleMapper.selectBatchIds(rids);
//            角色的修信息 角色管理 修改角色的名字
            List<SimpleGrantedAuthority> collect = tabRoles.stream().map(tabRole -> new SimpleGrantedAuthority("ROLE_" + tabRole.getRcode())).collect(Collectors.toList());
//            根据角色的id 查询菜单的mcode
            List<TabMenu> menus = menuMapper.selectCodeByRids(rids);
            List<SimpleGrantedAuthority> resources = menus.stream().map(tabMenu -> new SimpleGrantedAuthority(tabMenu.getMcode())).collect(Collectors.toList());
//            将角色的所有信息,和资源信息合并在一起
            List<SimpleGrantedAuthority> allresource = Stream.concat(collect.stream(), resources.stream()).collect(Collectors.toList());
            return new User(username, tabUser.getPassword(), allresource);
        }
        return null;
      }
}

7.获取用户的信息

/*
* 获取当前登录的用户的信息
* */
@RestController
public class UserController {
    @GetMapping("user1")
    @PreAuthorize("hasAnyAuthority('user:add')")
    public Object getUser(Principal principal) {
        return principal;
    }
    @GetMapping("user2")
    public Object getUser2(Authentication authentication){
        return authentication;
    }
    @GetMapping("user3")
    public Object getUser3() {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        return authentication;
    }
}

调试接口进行测试

Spring Security 中,可以通过实现 PermissionEvaluator 接口来自定义权限验证逻辑。 首先,需要在配置文件中开启自定义 PermissionEvaluator 的支持: ```xml <beans:bean id="expressionHandler" class="org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler"> <beans:property name="permissionEvaluator" ref="customPermissionEvaluator" /> </beans:bean> <beans:bean id="customPermissionEvaluator" class="com.example.CustomPermissionEvaluator" /> ``` 接下来,实现 PermissionEvaluator 接口的 evaluate 方法: ```java public class CustomPermissionEvaluator implements PermissionEvaluator { @Override public boolean hasPermission(Authentication authentication, Object targetDomainObject, Object permission) { // 在此处编写自定义的权限验证逻辑 } @Override public boolean hasPermission(Authentication authentication, Serializable targetId, String targetType, Object permission) { // 在此处编写自定义的权限验证逻辑 } } ``` 在 evaluate 方法中,第一个参数 authentication 表示当前用户的认证信息,第二个参数 targetDomainObject 表示要验证的对象,第三个参数 permission 表示要验证的权限。 如果要验证的对象是一个实体类,可以使用 @PreAuthorize 或 @PostAuthorize 注解配合 SpEL 表达式来进行验证: ```java @PreAuthorize("hasPermission(#entity, 'read')") public void doSomething(Entity entity) { // ... } ``` 在 SpEL 表达式中,可以使用 #parameterName 来引用方法参数,也可以使用 #returnObject 来引用方法返回值。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值