24AK

欢迎您的到来!!!

SpringBoot集成Spring Security(1)——入门程序

因为项目需要,第一次接触 Spring Security,早就听闻 Spring Security 功能强大但上手困难,学习了几天出入门道,特整理这篇文章希望能让后来者少踩一点坑(本文附带实例程序,请放心食用)


本篇文章环境:SpringBoot 2.0 + Mybatis + Spring Security 5.0


源码地址:https://github.com/jitwxs/blog_sample


文章目录

一、导入依赖

二、创建数据库

三、准备页面

四、配置application.properties

五、创建实体、Dao、Service和Controller

5.1 实体

5.2 Dao

5.3 Service

5.4 Controller

六、配置SpringSecurity

6.1 UserDetailsService

6.2 WebSecurityConfig

七、运行程序

一、导入依赖

导入 spring-boot-starter-security 依赖,在 SpringBoot 2.0 环境下默认使用的是 5.0 版本。


<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-web</artifactId>

</dependency>


<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-test</artifactId>

<scope>test</scope>

</dependency>


<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-security</artifactId>

</dependency>


<dependency>

<groupId>org.mybatis.spring.boot</groupId>

<artifactId>mybatis-spring-boot-starter</artifactId>

<version>1.3.1</version>

</dependency>


<dependency>

<groupId>mysql</groupId>

<artifactId>mysql-connector-java</artifactId>

</dependency>

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

二、创建数据库

一般权限控制有三层,即:用户<–>角色<–>权限,用户与角色是多对多,角色和权限也是多对多。这里我们先暂时不考虑权限,只考虑用户<–>角色。


创建用户表sys_user:


CREATE TABLE `sys_user` (

  `id` int(11) NOT NULL AUTO_INCREMENT,

  `name` varchar(255) NOT NULL,

  `password` varchar(255) NOT NULL,

  PRIMARY KEY (`id`)

) ENGINE=InnoDB DEFAULT CHARSET=utf8;

1

2

3

4

5

6

创建权限表sys_role:


CREATE TABLE `sys_role` (

  `id` int(11) NOT NULL,

  `name` varchar(255) NOT NULL,

  PRIMARY KEY (`id`)

) ENGINE=InnoDB DEFAULT CHARSET=utf8;

1

2

3

4

5

创建用户-角色表sys_user_role:


CREATE TABLE `sys_user_role` (

  `user_id` int(11) NOT NULL,

  `role_id` int(11) NOT NULL,

  PRIMARY KEY (`user_id`,`role_id`),

  KEY `fk_role_id` (`role_id`),

  CONSTRAINT `fk_role_id` FOREIGN KEY (`role_id`) REFERENCES `sys_role` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,

  CONSTRAINT `fk_user_id` FOREIGN KEY (`user_id`) REFERENCES `sys_user` (`id`) ON DELETE CASCADE ON UPDATE CASCADE

) ENGINE=InnoDB DEFAULT CHARSET=utf8;

1

2

3

4

5

6

7

8

初始化一下数据:


INSERT INTO `sys_role` VALUES ('1', 'ROLE_ADMIN');

INSERT INTO `sys_role` VALUES ('2', 'ROLE_USER');


INSERT INTO `sys_user` VALUES ('1', 'admin', '123');

INSERT INTO `sys_user` VALUES ('2', 'jitwxs', '123');


INSERT INTO `sys_user_role` VALUES ('1', '1');

INSERT INTO `sys_user_role` VALUES ('2', '2');

1

2

3

4

5

6

7

8

博主有话说:


这里的权限格式为ROLE_XXX,是Spring Security规定的,不要乱起名字哦。


三、准备页面

因为是示例程序,页面越简单越好,只用于登陆的login.html以及用于登陆成功后的home.html,将其放置在 resources/static 目录下:


(1)login.html:


<!DOCTYPE html>

<html>

<head>

    <meta charset="UTF-8">

    <title>登陆</title>

</head>

<body>

<h1>登陆</h1>

<form method="post" action="/login">

    <div>

        用户名:<input type="text" name="username">

    </div>

    <div>

        密码:<input type="password" name="password">

    </div>

    <div>

        <button type="submit">立即登陆</button>

    </div>

</form>

</body>

</html>

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

博主有话说:


用户的登陆认证是由Spring Security进行处理的,请求路径默认为/login,用户名字段默认为username,密码字段默认为password


(2)home.html:


<!DOCTYPE html>

<html>

<head>

    <meta charset="UTF-8">

    <title>Title</title>

</head>

<body>

    <h1>登陆成功</h1>

    <a href="/admin">检测ROLE_ADMIN角色</a>

    <a href="/user">检测ROLE_USER角色</a>

    <button onclick="window.location.href='/logout'">退出登录</button>

</body>

</html>

1

2

3

4

5

6

7

8

9

10

11

12

13

四、配置application.properties

在配置文件中配置下数据库连接:


spring.datasource.driver-class-name=com.mysql.jdbc.Driver

spring.datasource.url=jdbc:mysql://localhost:3306/security?useUnicode=true&characterEncoding=utf-8&useSSL=true

spring.datasource.username=root

spring.datasource.password=root


#开启Mybatis下划线命名转驼峰命名

mybatis.configuration.map-underscore-to-camel-case=true

1

2

3

4

5

6

7

五、创建实体、Dao、Service和Controller

5.1 实体

(1)SysUser


public class SysUser implements Serializable{

    static final long serialVersionUID = 1L;


    private Integer id;


    private String name;


    private String password;


    // 省略getter/setter

}

1

2

3

4

5

6

7

8

9

10

11

(2)SysRole


public class SysRole implements Serializable {

    static final long serialVersionUID = 1L;


    private Integer id;


    private String name;


    // 省略getter/setter

}

1

2

3

4

5

6

7

8

9

(3)SysUserRole


public class SysUserRole implements Serializable {

    static final long serialVersionUID = 1L;


    private Integer userId;


    private Integer roleId;


    // 省略getter/setter

}

1

2

3

4

5

6

7

8

9

5.2 Dao

(1)SysUserMapper


@Mapper

public interface SysUserMapper {

    @Select("SELECT * FROM sys_user WHERE id = #{id}")

    SysUser selectById(Integer id);


    @Select("SELECT * FROM sys_user WHERE name = #{name}")

    SysUser selectByName(String name);

}

1

2

3

4

5

6

7

8

(2)SysRoleMapper


@Mapper

public interface SysRoleMapper {

    @Select("SELECT * FROM sys_role WHERE id = #{id}")

    SysRole selectById(Integer id);

}

1

2

3

4

5

(3)SysUserRoleMapper


@Mapper

public interface SysUserRoleMapper {

    @Select("SELECT * FROM sys_user_role WHERE user_id = #{userId}")

    List<SysUserRole> listByUserId(Integer userId);

}

1

2

3

4

5

5.3 Service

(1)SysUserService


@Service

public class SysUserService {

    @Autowired

    private SysUserMapper userMapper;


    public SysUser selectById(Integer id) {

        return userMapper.selectById(id);

    }


    public SysUser selectByName(String name) {

        return userMapper.selectByName(name);

    }

}

1

2

3

4

5

6

7

8

9

10

11

12

13

(2)SysRoleService


@Service

public class SysRoleService {

    @Autowired

    private SysRoleMapper roleMapper;


    public SysRole selectById(Integer id){

        return roleMapper.selectById(id);

    }

}

1

2

3

4

5

6

7

8

9

(3)SysUserRoleService


@Service

public class SysUserRoleService {

    @Autowired

    private SysUserRoleMapper userRoleMapper;


    public List<SysUserRole> listByUserId(Integer userId) {

        return userRoleMapper.listByUserId(userId);

    }

}

1

2

3

4

5

6

7

8

9

5.4 Controller

@Controller

public class LoginController {

    private Logger logger = LoggerFactory.getLogger(LoginController.class);


    @RequestMapping("/")

    public String showHome() {

        String name = SecurityContextHolder.getContext().getAuthentication().getName();

        logger.info("当前登陆用户:" + name);


        return "home.html";

    }


    @RequestMapping("/login")

    public String showLogin() {

        return "login.html";

    }


    @RequestMapping("/admin")

    @ResponseBody

    @PreAuthorize("hasRole('ROLE_ADMIN')")

    public String printAdmin() {

        return "如果你看见这句话,说明你有ROLE_ADMIN角色";

    }


    @RequestMapping("/user")

    @ResponseBody

    @PreAuthorize("hasRole('ROLE_USER')")

    public String printUser() {

        return "如果你看见这句话,说明你有ROLE_USER角色";

    }

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

博主有话说:


如代码所示,获取当前登录用户:SecurityContextHolder.getContext().getAuthentication()


@PreAuthorize 用于判断用户是否有指定权限,没有就不能访问


六、配置SpringSecurity

6.1 UserDetailsService

首先我们需要自定义 UserDetailsService ,将用户信息和权限注入进来。


我们需要重写 loadUserByUsername 方法,参数是用户输入的用户名。返回值是UserDetails,这是一个接口,一般使用它的子类org.springframework.security.core.userdetails.User,它有三个参数,分别是用户名、密码和权限集。


实际情况下,大多将 DAO 中的 User 类继承 org.springframework.security.core.userdetails.User 返回。


@Service("userDetailsService")

public class CustomUserDetailsService implements UserDetailsService {

    @Autowired

    private SysUserService userService;


    @Autowired

    private SysRoleService roleService;


    @Autowired

    private SysUserRoleService userRoleService;


    @Override

    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {

        Collection<GrantedAuthority> authorities = new ArrayList<>();

        // 从数据库中取出用户信息

        SysUser user = userService.selectByName(username);


        // 判断用户是否存在

        if(user == null) {

            throw new UsernameNotFoundException("用户名不存在");

        }


        // 添加权限

        List<SysUserRole> userRoles = userRoleService.listByUserId(user.getId());

        for (SysUserRole userRole : userRoles) {

            SysRole role = roleService.selectById(userRole.getRoleId());

            authorities.add(new SimpleGrantedAuthority(role.getName()));

        }


        // 返回UserDetails实现类

        return new User(user.getName(), user.getPassword(), authorities);

    }

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

6.2 WebSecurityConfig

该类是 Spring Security 的配置类,该类的三个注解分别是标识该类是配置类、开启 Security 服务、开启全局 Securtiy 注解。


首先将我们自定义的 userDetailsService 注入进来,在 configure() 方法中使用 auth.userDetailsService() 方法替换掉默认的 userDetailsService。


这里我们还指定了密码的加密方式(5.0 版本强制要求设置),因为我们数据库是明文存储的,所以明文返回即可,如下所示:


@Configuration

@EnableWebSecurity

@EnableGlobalMethodSecurity(prePostEnabled = true)

public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired

    private CustomUserDetailsService userDetailsService;


    @Override

    protected void configure(AuthenticationManagerBuilder auth) throws Exception {

        auth.userDetailsService(userDetailsService).passwordEncoder(new PasswordEncoder() {

            @Override

            public String encode(CharSequence charSequence) {

                return charSequence.toString();

            }


            @Override

            public boolean matches(CharSequence charSequence, String s) {

                return s.equals(charSequence.toString());

            }

        });

    }


    @Override

    protected void configure(HttpSecurity http) throws Exception {

        http.authorizeRequests()

                // 如果有允许匿名的url,填在下面

//                .antMatchers().permitAll()

                .anyRequest().authenticated()

                .and()

                // 设置登陆页

                .formLogin().loginPage("/login")

                // 设置登陆成功页

                .defaultSuccessUrl("/").permitAll()

                // 自定义登陆用户名和密码参数,默认为username和password

//                .usernameParameter("username")

//                .passwordParameter("password")

                .and()

                .logout().permitAll();


        // 关闭CSRF跨域

        http.csrf().disable();

    }


    @Override

    public void configure(WebSecurity web) throws Exception {

        // 设置拦截忽略文件夹,可以对静态资源放行

        web.ignoring().antMatchers("/css/**", "/js/**");

    }

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49



七、运行程序

ROLE_ADMIN 账户:用户名 admin,密码 123

ROLE_USER 账户:用户名 jitwxs,密码 123




注:如果你想要将密码加密,可以修改 configure() 方法如下:


@Override

protected void configure(AuthenticationManagerBuilder auth) throws Exception {

     auth.userDetailsService(userDetailsService)

         .passwordEncoder(new BCryptPasswordEncoder());

 }

1

2

3

4

5

点赞 52

————————————————

版权声明:本文为CSDN博主「Jitwxs」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。

原文链接:https://blog.csdn.net/yuanlaijike/article/details/80249235


«   2019年12月   »
1
2345678
9101112131415
16171819202122
23242526272829
3031
控制面板
您好,欢迎到访网站!
  查看权限
网站分类
搜索

Powered By Z-BlogPHP 1.5.2 Zero

24AK!!备案号:粤ICP备19155665号