简单且实用的spring security认证和授权(国庆day3)

1 认证

Spring Security认证分为两种:表单认证(如用户名、密码),HTTP基础认证,就是把账号信息放到请求头。

1.1 认证过程

认证过程如下图,我们可以按照下图来编写认证的代码,构建Authentication是框架帮我做的,我们接着往下写代码。

在这里插入图片描述

1.2 表单认证

1.2.1 配置AuthenticationManager

public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    SysUserRepository sysUserRepository;
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(new CusotmUserDetailsService(sysUserRepository));
    }
}

1.2.2 编写UserDetailsService

UserDetailsService依赖于UserDetailsRepository,UserDetailsResposity依赖于SysUser对象。
用户的实体:

@Data
@AllArgsConstructor
@NoArgsConstructor
@Entity
public class SysUser implements UserDetails {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String realName;

    @Column(unique = true)
    private String username;

    private String password;

    private String role;

    public SysUser(String realName, String username, String password, String role) {
        this.realName = realName;
        this.username = username;
        this.password = password;
        this.role = role;
    }

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
      return null;
    }

    @Override
    public String getPassword() {
        return this.password;
    }

    @Override
    public String getUsername() {
        return this.username;
    }

    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }

    @Override
    public boolean isEnabled() {
        return true;
    }
}

用户的Repository:

public interface SysUserRepository extends JpaRepository<SysUser, Long> {
   Optional<SysUser> findByUsername(String username);
}

UserDetailsService:

public class CusotmUserDetailsService implements UserDetailsService {

    SysUserRepository sysUserRepository;

    public CusotmUserDetailsService(SysUserRepository sysUserRepository) {
        this.sysUserRepository = sysUserRepository;
    }
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        Optional<SysUser> sysUserOptional = sysUserRepository.findByUsername(username);
        return  sysUserOptional
                .orElseThrow(() -> new UsernameNotFoundException("Username not found"));
    }

1.2.3 编写控制器测试

 @GetMapping("/")
    public String hello(){
        return "Hello Spring Security";
    }

在这里插入图片描述

1.3 HTTP基础认证

HTTP基础认证过程和表单认证过程机器相似,唯一修改的地方就是添加一个新的HTTP基础认证的AuthenticationManager。

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/everyCanAccess").permitAll()
                .and()
                .httpBasic().authenticationEntryPoint(authenticationEntryPoint());
    }

在请求头上添加账户信息,信息为Basic+用户名:密码的Base64编码
在这里插入图片描述

1.4 密码编码

在webSecurityConfig添加编码容器

  @Bean
    PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }

2 授权

授权分为两种:用户角色授权和方法授权

2.1 授权过程

认证完成之后进行授权,授权需要从数据库中查询当前认证用户所属的角色,然后根据角色的权限,判断该用户是否有权限访问资源。
在这里插入图片描述

2.2 用户授权

2.2.1 配置Web路径的安全访问

@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    SysUserRepository sysUserRepository;
/*    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(new CusotmUserDetailsService(sysUserRepository));
    }*/

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/everyCanAccess").permitAll()
                .antMatchers("/authenticatedCanAccess").authenticated()
                .antMatchers("/adminCanAccess").hasRole("ADMIN")
                .antMatchers("/userCanAccess").access("hasRole('USER') or hasRole('ADMIN')")
                .antMatchers("/threeCanAccess").access("@webSecurity.checkUsernameLenEq3(authentication)")
                .anyRequest().authenticated()
                .and()
                .httpBasic().authenticationEntryPoint(authenticationEntryPoint());
    }

    @Bean
    UserDetailsService userDetailsService(SysUserRepository sysUserRepository){
        return new CusotmUserDetailsService(sysUserRepository);
    }

    @Bean
    AuthenticationEntryPoint authenticationEntryPoint(){
        BasicAuthenticationEntryPoint authenticationEntryPoint = new BasicAuthenticationEntryPoint();
        authenticationEntryPoint.setRealmName("wisely");
        return authenticationEntryPoint;
    }

    @Bean
    PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }
}

配置属性总共包括以下几种:

  • access(String) 如果给定的SpEL表达式计算结果为true,就允许访问
  • anonymous() 允许匿名用户访问
  • authenticated() 允许认证的用户进行访问
  • denyAll() 无条件拒绝所有访问
  • fullyAuthenticated() 如果用户是完整认证的话(不是通过Remember-me功能认证的),就允许访问
  • hasAuthority(String) 如果用户具备给定权限的话就允许访问
  • hasAnyAuthority(String…)如果用户具备给定权限中的某一个的话,就允许访问
  • hasRole(String) 如果用户具备给定角色(用户组)的话,就允许访问
  • hasAnyRole(String…) 如果用户具有给定角色(用户组)中的一个的话,允许访问.
  • hasIpAddress(String 如果请求来自给定ip地址的话,就允许访问.
  • not() 对其他访问结果求反.
  • permitAll() 无条件允许访问
  • rememberMe() 如果用户是通过Remember-me功能认证的,就允许访问

2.2.2 重写SysUser

重写UserDetails的getAuthorities方法或缺的用户角色

@Data
@AllArgsConstructor
@NoArgsConstructor
@Entity
public class SysUser implements UserDetails {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String realName;

    @Column(unique = true)
    private String username;

    private String password;

    private String role;

    public SysUser(String realName, String username, String password, String role) {
        this.realName = realName;
        this.username = username;
        this.password = password;
        this.role = role;
    }

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        Collection<SimpleGrantedAuthority> authorities = new ArrayList<>();
        SimpleGrantedAuthority authority = new SimpleGrantedAuthority(this.role);
        authorities.add(authority);
        return authorities;
    }

    @Override
    public String getPassword() {
        return this.password;
    }

    @Override
    public String getUsername() {
        return this.username;
    }

    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }

    @Override
    public boolean isEnabled() {
        return true;
    }
}

2.2.3 编写控制器

@RestController
public class IndexController {


    @GetMapping("/")
    public String hello(){
        return "Hello Spring Security";
    }

    @GetMapping("/user")
    public Map<String, Object> getUserInfo(@AuthenticationPrincipal SysUser sysUser,
                                           @CurrentSecurityContext SecurityContext securityContext,
                                           @CurrentSecurityContext(expression = "authentication") Authentication authentication ){
        SecurityContext context = SecurityContextHolder.getContext();
        Authentication auth = context.getAuthentication();
        Object principal = auth.getPrincipal();
        Object details = auth.getDetails();
        Map<String, Object> map = new HashMap<>();
        map.put("sysUser", sysUser);
        map.put("authentication", authentication);
        map.put("principal", principal);
        map.put("details", details);
        return map;
    }

    @GetMapping("/everyCanAccess")
    public String everyCanAccess(){
        return "任何用户可访问";
    }

    @GetMapping("/authenticatedCanAccess")
    public String authenticatedCanAccess(){
        return "任何登录用户可访问";
    }

    @GetMapping("/userCanAccess")
    public String userCanAccess(){
        return "角色为ROLE_USER或ROLE_ADMIN的用户都可访问";
    }

    @GetMapping("/adminCanAccess")
    public String adminCanAccess(){
        return "角色为ROLE_ADMIN用户可访问";
    }

    @GetMapping("/threeCanAccess")
    public String threeCanAccess(){
        return "只有用户名字符串长度为3的用户可以访问";
    }
}

测试:
在这里插入图片描述

2.3 方法授权

2.3.1 开启方法授权

@EnableGlobalMethodSecurity(prePostEnabled = true)

2.3.2 方法授权的不同注解

  • @PreAuthorize --适合进入方法之前验证授权
  • @PostAuthorize --检查授权方法之后才被执行
  • @PostFilter --在方法执行之后执行,而且这里可以调用方法的返回值,然后对返回值进行过滤或处理或修改并返回
  • @PreFilter --在方法执行之前执行,而且这里可以调用方法的参数,然后对参数值进行过滤或处理或修改

2.3.3 给方法授权

@RestController
public class IndexController {


    @GetMapping("/")
    public String hello(){
        return "Hello Spring Security";
    }

    @GetMapping("/user")
    public Map<String, Object> getUserInfo(@AuthenticationPrincipal SysUser sysUser,
                                           @CurrentSecurityContext SecurityContext securityContext,
                                           @CurrentSecurityContext(expression = "authentication") Authentication authentication ){
        SecurityContext context = SecurityContextHolder.getContext();
        Authentication auth = context.getAuthentication();
        Object principal = auth.getPrincipal();
        Object details = auth.getDetails();
        Map<String, Object> map = new HashMap<>();
        map.put("sysUser", sysUser);
        map.put("authentication", authentication);
        map.put("principal", principal);
        map.put("details", details);
        return map;
    }

    @GetMapping("/everyCanAccess")
    public String everyCanAccess(){
        return "任何用户可访问";
    }

    @GetMapping("/authenticatedCanAccess")
    public String authenticatedCanAccess(){
        return "任何登录用户可访问";
    }

    @GetMapping("/userCanAccess")
    public String userCanAccess(){
        return "角色为ROLE_USER或ROLE_ADMIN的用户都可访问";
    }

    @GetMapping("/adminCanAccess")
    public String adminCanAccess(){
        return "角色为ROLE_ADMIN用户可访问";
    }

    @GetMapping("/threeCanAccess")
    public String threeCanAccess(){
        return "只有用户名字符串长度为3的用户可以访问";
    }


    @GetMapping("/methodAdmin")
    @PreAuthorize("hasRole('ADMIN')")
    public String methodAdmin(){
        return "只有角色为ROLE_ADMIN的用户可访问";
    }

    @GetMapping("/methodDiffName")
    @PreAuthorize("#user.username != authentication.name")
    public String methodDiffName(@RequestBody SysUser user){
        return "传输的用户名和当前用户名不相同的可访问";
    }

    @GetMapping("/methodNameThree")
    @PreAuthorize("@webSecurity.checkUsernameLenEq3(authentication)")
    public String methodNameThree(){
        return "只有用户名字符串长度为3的用户可以访问";
    }

    @GetMapping("/methodAnotherName3")
    @PostAuthorize("returnObject.length() == 5")
    public String anotherTree(@AuthenticationPrincipal SysUser sysUser){
        return "Hi" + sysUser.getUsername();
    }

    @GetMapping("/methodFilterIn")
    @PreAuthorize("hasRole('USER')")
    @PreFilter("filterObject%2 == 0")
    public List<Integer> methodFilterIn (@RequestParam List<Integer> numbers){
        return numbers;
    }

    @GetMapping("/methodFilterOut")
    @PostFilter("hasRole('USER') and filterObject%2 == 0")
    public Integer[] methodFilterIn (){
        Integer[] numbers = {1,2,3,4,5,6,7,8,9};
        return numbers;
    }
}

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值