Java阶段三Day07

Java阶段三Day07

Spring Security

自定义UserDetails

  1. 默认的UserDetails里面只有用户的用户名,没有其它的信息。如果需要用到类似id和nickname等信息的话需要自定义UserDetails
  2. 修改UserDetailServiceImpl中的UserDetails,并把后期需要的id和nickName保存进去
  • UserDetailServiceImpl
@Service
public class UserDetailServiceImpl implements UserDetailsService {

    @Resource
    private UserMapper userMapper;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        UserVO user = userMapper.selectByUsername(username);
        if (user == null) {
            return null;    //默认抛出 AuthenticationException 用户名找不到异常
        }

        List<GrantedAuthority> list = AuthorityUtils.createAuthorityList("权限1", "权限2");
        //创建自定义的UserDetails并把后期需要的id和nickName保存进去
        CustomUserDetails userDetail = new CustomUserDetails(
                user.getId(),
                user.getNickname(),
                username,
                user.getPassword(),
                list
        );
        //如果用户输入的密码和数据库中查询到的密码不一致则会抛出异常
        return userDetail;
    }
}
  • CustomUserDetails
@Getter
@ToString
public class CustomUserDetails extends User {
    private Integer id;
    private String nickname;
    public CustomUserDetails(Integer id,String nickname,String username, String password, Collection<? extends GrantedAuthority> authorities) {
        super(username, password, authorities);
        this.id = id;
        this.nickname = nickname;
    }
}
  • WeiboController
@RestController
@RequestMapping("/v1/weibos")
public class WeiboController {

    @Resource
    private WeiboMapper weiboMapper;

    @PostMapping("/insert")
    public ResultVO reg(@RequestBody WeiboDTO weiboDTO, @AuthenticationPrincipal CustomUserDetails userDetails){
        System.out.println("weiboDTO = " + weiboDTO + ", userDetails = " + userDetails);
        Weibo weibo = new Weibo();
        BeanUtils.copyProperties(weiboDTO, weibo);
        weibo.setCreated(new Date());
        //作者id  当前登录的用户id,从Security框架中得到当前登录的用户信息
        weibo.setUserId(userDetails.getId());
        weiboMapper.insert(weibo);
        return new ResultVO(StatusCode.SUCCESS);
    }
}

密码加密

  1. SecurityConfig配置类中配置密码加密方式 return new BCryptPasswordEncoder();
  2. UserController中添加PasswordEncoder自动装配,并在注册功能中对user对象里面的密码进行加密
  • SecurityConfig
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    //配置密码加密的方式
    @Bean
    public PasswordEncoder passwordEncoder(){
        //NoOpPasswordEncoder.getInstance()获取一个无加密的实例
        //返回此加密的编码器之后, 用户输入的密码会通过此编码器加密之后再和数据库里面的密码进行比较
        return new BCryptPasswordEncoder();

    }
}
  • UserController
@RestController
@RequestMapping("/v1/users")
public class UserController {

    @Autowired
    PasswordEncoder passwordEncoder;

    @Resource
    private UserMapper userMapper;

    @PostMapping("/reg")
    public ResultVO reg(@RequestBody UserRegDTO userRegDTO){
        UserVO userVO = userMapper.selectByUsername(userRegDTO.getUsername());
        if(userVO!= null){
            return new ResultVO(StatusCode.USERNAME_ALREADY_EXISTS);
        }
        User user = new User();
        BeanUtils.copyProperties(userRegDTO, user);
        user.setCreated(new Date());
        //对user对象里面的密码进行加密 -- 加密之后得到60个字符长度的密码
        user.setPassword(passwordEncoder.encode(user.getPassword()));
        userMapper.insert(user);
        return new ResultVO(StatusCode.SUCCESS);
    }
}

授权

  1. UserDetailsServicelmpl中用户登录认证时,给当前用户设置拥有的权限
  2. SecurityConfig配置类中添加授权检测的注解@EnableGlobalMethodSecurity(prePostEnabled = true)
  3. WeiboController中处理请求的方法上面添加注解判断当前登录的用户是否拥有此权限,如果有,允许访问。如果没有则抛出异常
  4. 在统一全局异常处理GlobalExceptionHandler处理异常
  • UserDetailsServicelmpl
@Service
public class UserDetailServiceImpl implements UserDetailsService {

    @Resource
    private UserMapper userMapper;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        UserVO user = userMapper.selectByUsername(username);
        if (user == null) {
            return null;    //默认抛出 AuthenticationException 用户名找不到异常
        }

        //模拟王五是管理员,其他是用户
        String role = username.equals("王五") ? "ADMIN" : "USER";
        List<GrantedAuthority> list = AuthorityUtils.createAuthorityList(role);
        //创建自定义的UserDetails并把后期需要的id和nickName保存进去
        CustomUserDetails userDetail = new CustomUserDetails(
            user.getId(),
            user.getNickname(),
            username,
            user.getPassword(),
            list
        );

        //如果用户输入的密码和数据库中查询到的密码不一致则会抛出异常
        return userDetail;
    }
}
  • SecurityConfig
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)//开启方法授权的检测
public class SecurityConfig extends WebSecurityConfigurerAdapter {

}
  • WeiboController
@RestController
@RequestMapping("/v1/weibos")
public class WeiboController {

    @Resource
    private WeiboMapper weiboMapper;

    @PostMapping("/{id}/delete")
    //@PreAuthorize 当前用户必须拥有 ADMIN 权限才能删除,否则会抛出异常
    @PreAuthorize("hasAnyAuthority('ADMIN')")
    public ResultVO delete(@PathVariable Integer id){
        weiboMapper.deleteById(id);
        return new ResultVO(StatusCode.SUCCESS);
    }
}
  • GlobalExceptionHandler
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {
    /**
     * 用户无权访问抛出异常
     */
    @ExceptionHandler(AccessDeniedException.class)
    public ResultVO handleAccessDeniedException(AccessDeniedException e){
        log.warn("无权访问!");
        return new ResultVO(StatusCode.FORBIDDEN_ERROR);
    }
}

JDK包结构

  • 为了便于使用和维护,JDK类库按照包结构划分,不同功能的类划分在不同的包中

  • 经常使用的包如下表所示

    功能
    java.langJava程序的基础类,如字符串、多线程等,该包中的类使用的频率非常高,不需要import,可以直接使用
    java.util常用工具类,如集合、随机数产生器、日历、时钟等
    java.io文件操作、输入/输出操作
    java.net网络操作
    java.math数学运算相关操作
    java.security安全相关操作
    java.sql数据库访问
    java.text处理文字、日期、数字、信息的格式

文档注释规范

  • /**开始,以*/结束
  • 加在类和方法的开头,用于说明作者,时间,版本,要实现功能的详细描述等信息
  • 通过javadoc工具,可以轻松的将此注释转换为HTML文档说明;学习者和程序员主要通过文档了解API的功能
  • 文档注释不同于普通的注释(/…或//),普通注释写在程序之中,用于程序员进行代码维护和交流,无法通过工具生成文档;而文档注释(/**…*/)写在类和方法的开头,专门用于生成供API使用者进行参考的文档资料

JDK API

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

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

String API

String是不可变对象

  • java.lang.String使用了final修饰,不能被继承
  • 字符串底层封装了字符数组及针对字符数组的操作算法
  • 字符串一旦创建,对象永远无法改变,但字符串引用可以重新赋值
  • Java字符串在内存中采用Unicode编码方式,任何一个字符对应两个字节的定长编码

String常量池

  • Java为了提高性能,静态字符串(字面量 / 常量 / 常量连接的结果)在常量池中创建,并尽量使用同一个对象,重用静态字符串
  • 对于重复出现的字符串直接量,JVM会首先在常量池中查找,如果存在即返回该对象。

内存编码及长度

  • String在内存中采用Unicode编码,每个字符占用两个字节
  • 任何一个字符(无论中文还是英文)都算1个字符长度,占用两个字节。

使用indexOf实现检索

  • indexOf方法用于实现在字符串中检索另外一个字符串

  • String提供几个重载的indexOf方法

    方法功能描述
    int indexOf(String str)在字符串中检索str,返回其第一次出现的位置,如果找不到则返回-1
    int indexOf(String str,int fromIndex)从字符串的 fromIndex位置开始检索
  • String还定义了lastIndexOf方法

    方法功能描述
    int lastIndexOf(String str,int from)str在字符串中多次出现时,将返回最后一个出现的位置

使用substring获取子串

  • substring方法用于返回一个字符串的子字符串

  • substring方法常用重载方法定义如下

    方法功能描述
    String substring(int beginIndex,int endIndex)返回字符串中从下标beginlndex(包括)开始到endlndex(不包括)结束的子字符串
    String substring(int beginIndex)返回字符串中从下标beginIndex(包括)开始到字符串结尾的子字符串

trim去除两侧空白

trim方法用于去掉一个字符串的前导和后继空字符

charAt

方法功能描述
char charAt(int index)方法charAt()用于返回字符串指定位置的字符,参数index表示指定的位置

startsWith和endsWith

用于检测一个字符串是否以指定字符串开头或结尾

大小写变换

用于转换字符串中英文字母的大小写形式

valueOf

  • String提供了若干的静态的重载方法valueOf
  • 该方法用于将其他类型转换为字符串类型

StringBuilder API

StringBuilder封装可变字符串

  • StringBuilder封装可变的字符串,对象创建后可以通过调用方法改变其封装的字符序列
  • StringBuilder常用构造方法:
    • public StringBuilder()
    • public StringBuilder(String str)

StringBuilder常用方法

常用方法功能描述
StringBuilder append(String str)追加字符串
StringBuilder append(int dstOffset,String s)插入字符串
StringBuilder append(int start,int end)删除字符串
StringBuilder replace(int start,int end,String str)替换字符串
StringBuilder reverse()字符串反转

StringBuild总结

  • StringBuilder可变字符串。字符串的内容计算,建议采用StringBuilder实现,这样性能会好一些

  • java的字符串连接的过程是利用StringBuilder实现的

    String s = "AB" ;String s1 = s +"DE"+1;
    String s1 = new StringBuilder(s). append ( "DE")append(1).toString () ;
    
  • StringBufferStringBuilder

    • StringBuffer线程安全的,同步处理的,性能稍
    • StringBuilder非线程安全的,并发处理的,性能稍

教师总结

获取当前登录的用户信息

  1. 如果需要获取用户名以外的信息, 需要自定义CustomUserDetails,
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-B4YLAVWu-1685520612559)(C:\Users\TEACHER\Downloads\jsd-2303-04-teacher-master\文件\笔记\image-20230531154550611.png)]

  2. 在UserDetailServiceImpl里面 把之前创建的UserDetails换成CustomUserDetails

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mQeb27Pi-1685520612561)(C:\Users\TEACHER\Downloads\jsd-2303-04-teacher-master\文件\笔记\image-20230531154716332.png)]

  3. 在WeiboController中发微博的方法参数列表处声明CustomUserDetails,获取当前登录用户的信息

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GQap7bkM-1685520612562)(C:\Users\TEACHER\Downloads\jsd-2303-04-teacher-master\文件\笔记\image-20230531154917443.png)]

授权

  1. 在UserDetailsServiceImpl中 用户登录认证时,给当前用户设置拥有的权限
    ​	[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HJGiSQLI-1685520612563)(C:\Users\TEACHER\Downloads\jsd-2303-04-teacher-master\文件\笔记\image-20230531155112074.png)]

  2. 在Security配置类中添加授权检测的注解

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Gq6evYyh-1685520612564)(C:\Users\TEACHER\Downloads\jsd-2303-04-teacher-master\文件\笔记\image-20230531155155559.png)]

  3. 在WeiboController中处理请求的方法上面添加注解 判断当前登录的用户是否拥有此权限,如果有,运行访问. 如果没有则抛出异常

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ekobuAXE-1685520612565)(C:\Users\TEACHER\Downloads\jsd-2303-04-teacher-master\文件\笔记\image-20230531155322826.png)]

  4. 在全局异常处理类中 处理异常

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WtTrDsVm-1685520612567)(C:\Users\TEACHER\Downloads\jsd-2303-04-teacher-master\文件\笔记\image-20230531155402804.png)]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

今天你学Java了吗

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值