SpringBoot Security首次学习探索

SpringBoot Security学习

一、创建环境

1.创建SpringBoot项目,导入依赖

在这里插入图片描述

如果这里选了security的依赖,在访问时要先通过security的默认验证,用户名user,密码可以在控制台找到。

记得添加mybatis的依赖哦

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

2.创建数据库

2.1建库
create table user
(
	id int auto_increment,
	username varchar(255) null,
	password varchar(255) null,
	role varchar(255) null,
	constraint user_pk
		primary key (id)
);

在这里插入图片描述

2.3添加配置信息
spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/security
    username: root
    password: 123
logging:
  level: 
    com.example.security.mapper: debug

3.创建基础类

3.1 创建User
package com.example.security.pojo;

import lombok.Data;

/**
 * FileName:com.example.security.domain
 * Author:70968
 * Date:2021-04-11 11:29
 * History
 */
@Data
public class User {
    private int id;
    private String username;
    private String password;
    private String role;
}

3.2 创建mapper
package com.example.security.mapper;

import com.example.security.pojo.User;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import org.springframework.stereotype.Repository;

/**
 * FileName:com.example.security.mapper
 * Author:70968
 * Date:2021-04-11 11:34
 * History
 */
@Mapper
@Repository
public interface UserMapper {
    @Select("select * from user where username = #{username}")
    User getUserInfoByUsername(String username);
    
    @Select("select role from user where username= #{username}")
    String getUserRoleByUsername(String username);
}

3.3 创建service
package com.example.security.service;

import com.example.security.mapper.UserMapper;
import com.example.security.pojo.User;
import org.springframework.beans.factory.annotation.Autowired;

/**
 * FileName:com.example.security.service
 * Author:70968
 * Date:2021-04-11 11:43
 * History
 */
public class UserService {
    @Autowired
    private UserMapper userMapper;

    public User getUser(String username){
        return userMapper.getUserInfoByUsername(username);
    }
    
    public String getRole(String username) {
        return userMapper.getUserRoleByUsername(username);
    }

}

3.3 创建Controller
package com.example.security.controller;

import com.example.security.pojo.User;
import com.example.security.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

/**
 * FileName:com.example.security.controller
 * Author:70968
 * Date:2021-04-11 11:46
 * History
 */
@RestController
public class HelloController {
    @Autowired
    private UserService userService;

    @GetMapping("getUser")
    public User getUser(@RequestParam String username){
        return userService.getUser(username);
    }
}

4.环境测试

访问 http://localhost:8080/get-user?username=admin

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CNNQJO4J-1618746211125)(C:\Users\70968\AppData\Roaming\Typora\typora-user-images\image-20210418102538126.png)]

二、创建security配置类

测试环境完成后,接下来需要配置security,实现数据库验证

1.CustomUserDetailsService类

实现从数据库读取用户信息需要实现UserDetailService接口,并且重写他的方法loadUserByUsername()

package com.example.security.service;

import com.example.security.pojo.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;

@Component
public class CustomUserDetailsService implements UserDetailsService {
    @Autowired
    private UserService userService;

    /**
     * 需新建配置类注册一个指定的加密方式Bean,或在下一步Security配置类中注册指定
     */
    @Autowired
    private PasswordEncoder passwordEncoder;

    @Override
    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
        //通过用户名从数据库获取用户信息
        User user = userService.getUser(s);
        if (user == null) {
            throw new UsernameNotFoundException("用户不存在");
        }

        // 得到用户角色
        String role = userService.getRole(s);

        // 角色集合
        List<GrantedAuthority> authorities = new ArrayList<>();
        // 角色必须以`ROLE_`开头,数据库中没有,则在这里加
        authorities.add(new SimpleGrantedAuthority("ROLE_" + role));

        return new org.springframework.security.core.userdetails.User(
                user.getUsername(),
                // 因为数据库是明文,所以这里需加密密码
                passwordEncoder.encode(user.getPassword()),
                authorities
        );
    }
}

2.MyUserDatailService

该类用于获取符合security要求的用户信息

package com.example.security.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;

@Component
public class MyUserDatailService implements UserDetailsService {
    @Autowired
    private UserService userService;
    /**
     * 需新建配置类注册一个指定的加密方式Bean,或在下一步Security配置类中注册指定
     */
    @Autowired
    private PasswordEncoder passwordEncoder;

    @Override
    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
        com.example.security.pojo.User user = userService.getUser(s);
        // 得到用户角色
        String role = userService.getRole(s);

        // 角色集合
        List<GrantedAuthority> authorities = new ArrayList<>();
        // 角色必须以`ROLE_`开头,数据库中没有,则在这里加
        authorities.add(new SimpleGrantedAuthority("ROLE_" + role));

        return new User(
                user.getUsername(),
                // 数据库密码已加密,不用再加密
                passwordEncoder.encode(user.getPassword()),
                authorities
        );
    }
}

3.WebSecurityConfig

创建Security的配置类WebSecurityConfig继承WebSecurityConfigurerAdapter,并重写configure(auth)方法

package com.example.security.config;

import com.example.security.service.MyUserDatailService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true) // 开启方法级安全验证
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    private MyUserDatailService userDetailService;

    /**
     * 指定加密方式
     */
    @Bean
    public PasswordEncoder passwordEncoder(){
        // 使用BCrypt加密密码
        return new BCryptPasswordEncoder();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth
                // 从数据库读取的用户进行身份认证
                .userDetailsService(userDetailService)
                .passwordEncoder(passwordEncoder());
    }
}

完成以上三个类后,就可以重启启动项目,通过数据库的用户名和密码进行验证了。

三、角色访问控制

完成通过数据库来限制用户登录后,进行角色限制访问

1.开启角色访问

开启方法:在WebSecurityConfig添加注解:

@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true) // 开启方法级安全验证
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
..
}

2.修改Controller

添加角色访问路径

package com.example.security.controller;

import com.example.security.pojo.User;
import com.example.security.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

/**
 * FileName:com.example.security.controller
 * Author:70968
 * Date:2021-04-11 11:46
 * History
 */
@RestController
public class HelloController {
    @Autowired
    private UserService userService;

    @GetMapping("/get-user")
    public User getUser(@RequestParam String username){
        return userService.getUser(username);
    }

    @PreAuthorize("hasAnyRole('user')") // 只能user角色才能访问该方法
    @GetMapping("/user")
    public String user(){
        return "user角色访问";
    }

    @PreAuthorize("hasAnyRole('admin')") // 只能admin角色才能访问该方法
    @GetMapping("/admin")
    public String admin(){
        return "admin角色访问";
    }
}

完成后重启测试

四、密码加密保存

在实际开发中用户密码是需要加密的。

1.简单的加密

1.1向mapper中添加sql
package com.example.security.mapper;

import com.example.security.pojo.User;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import org.springframework.stereotype.Component;

/**
 * FileName:com.example.security.mapper
 * Author:70968
 * Date:2021-04-11 11:34
 * History
 */
@Component
@Mapper
public interface UserMapper {
    @Select("select * from user where username = #{username}")
    User getUserInfoByUsername(String username);

    @Select("select role from user where username= #{username}")
    String getUserRoleByUsername(String username);

    @Insert("insert into user(username,password,role) value (#{username},#{password},#{role})")
    int insertUser(User user);
}
1.2向service中添加
package com.example.security.service.impl;

import com.example.security.mapper.UserMapper;
import com.example.security.pojo.User;
import com.example.security.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

/**
 * FileName:com.example.security.service.impl
 * Author:70968
 * Date:2021-04-11 12:21
 * History
 */
@Service("userService")
public class UserServiceImpl implements UserService {
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private PasswordEncoder passwordEncoder;

    @Override
    public User getUser(String username) {
        return userMapper.getUserInfoByUsername(username);
    }

    @Override
    public String getRole(String username) {
        return userMapper.getUserRoleByUsername(username);
    }

    @Override
    public int insertUser(User user) {
        user.setPassword(passwordEncoder.encode(user.getPassword()));
        return userMapper.insertUser(user);
    }

}
1.3添加添加用户的Controller
package com.example.security.controller;

import com.example.security.pojo.User;
import com.example.security.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;

/**
 * FileName:com.example.security.controller
 * Author:70968
 * Date:2021-04-11 11:46
 * History
 */
@RestController
public class HelloController {
    @Autowired
    private UserService userService;

    @GetMapping("/get-user")
    public User getUser(@RequestParam String username){
        return userService.getUser(username);
    }

    @PreAuthorize("hasAnyRole('user')") // 只能user角色才能访问该方法
    @GetMapping("/user")
    public String user(){
        return "user角色访问";
    }

    @PreAuthorize("hasAnyRole('admin')") // 只能admin角色才能访问该方法
    @GetMapping("/admin")
    public String admin(){
        return "admin角色访问";
    }

    @PostMapping("/add-user")
    public int addUser(@RequestBody User user){
        return userService.insertUser(user);
    }
}

重启测试,用postman发送请求
在这里插入图片描述

显示没有权限。需要重新修改WebSecurityConfig配置类

重启项目发送请求

在这里插入图片描述

2.使用加密密码登录

2.1修改MyUserDetailService

删掉加密

package com.example.security.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;

@Component
public class MyUserDetailService implements UserDetailsService {
    @Autowired
    private UserService userService;
    /**
     * 需新建配置类注册一个指定的加密方式Bean,或在下一步Security配置类中注册指定
     */
    @Autowired
    private PasswordEncoder passwordEncoder;

    @Override
    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
        com.example.security.pojo.User user = userService.getUser(s);
        // 得到用户角色
        String role = userService.getRole(s);

        // 角色集合
        List<GrantedAuthority> authorities = new ArrayList<>();
        // 角色必须以`ROLE_`开头,数据库中没有,则在这里加
        authorities.add(new SimpleGrantedAuthority("ROLE_" + role));

        return new User(
                user.getUsername(),
                // 数据库密码已加密,不用再加密
                user.getPassword(),
                authorities
        );
    }
}

关于MyUserDetailService和CustomUserDetailsService的区别
用一个就可以了,如果数据库密码是明文,需要用CustomUserDetailsService加密。
如果数据库密码已经加密,用MyUserDetailService。

五、修改密码

1.修改代码

service方法中添加

@Override
    public int updatePwd(String oldPwd, String newPwd) {
        UserDetails principal = (UserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        String username = principal.getUsername();
        User user = userMapper.getUserInfoByUsername(username);
        if (passwordEncoder.matches(oldPwd,user.getPassword())){
            return userMapper.updatePwd(user.getUsername(), passwordEncoder.encode(newPwd));
        }
        return 0;
    }

mapper中添加

 @Update("update user set password=#{newPwd} where username = #{username}")
    int updatePwd(String username,String newPwd);

controller中添加

@PutMapping("/updatePwd")
    public int updatePwd(@RequestBody Map<String,String> map){
        return userService.updatePwd(map.get("oldPwd"),map.get("newPwd"));
    }

2.访问测试

用postman测试
首先在网页访问http://localhost:8080/,登陆后复制jsession
在这里插入图片描述
将jsession粘贴找postman中
在这里插入图片描述
发送改密请求
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值