关于springsecurity:Spring-Security-之学习路途

32次阅读

共计 6172 个字符,预计需要花费 16 分钟才能阅读完成。

Spring Security 学习之旅开始

SpringSecurity 开始

我的项目:Github

1. 引入依赖

   <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.4.1</version>
        <relativePath/> 
   </parent>
  <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-security</artifactId>
  </dependency>

在 manven 依赖仓库中:

2. 配置 Security

1. 在包下创立 SecurityCconfig 类, 重写 configure 办法,其中 WebSecurity web,能够定义疏忽门路

 @Override
    public void configure(WebSecurity web) throws Exception {
        // 疏忽拦挡
        web.ignoring().antMatchers("/sayHello","/doLogin");
    }
  1. HttpSecurity http 能够拦挡申请, 能够定义登录、登出等等
 @Override
    protected void configure(HttpSecurity http) throws Exception {http.authorizeRequests()// 开启登录
               // 示意拜访,ex/index 这个接口,须要具备 admin 角色
                .antMatchers("/es/**").hasRole("admin")
               // 示意残余的其余接口,登录之后能拜访
                .anyRequest().authenticated()
                .and()
                .formLogin()
                .loginPage("/login")
               // 登录解决接口
                .loginProcessingUrl("/doLogin")
               // 定义登录时,用户名的 key,默认为 username
                .usernameParameter("username")
               // 定义登录时,用户明码的 key,默认为 password
                .passwordParameter("password")
               // 定义登录胜利的处理器
                .successHandler(new AuthenticationSuccessHandler() {
                    @Override
                    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {response.setContentType("application/json;charset=utf-8");
                        response.sendRedirect("/success.html");// 重定向到一个页面
                        MyUserDetails detail= (MyUserDetails)authentication.getPrincipal();
                        System.out.println(detail);
                    }
                })
                .failureHandler(new AuthenticationFailureHandler() {
                    @Override
                    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {response.setContentType("application/json;charset=utf-8");
                        PrintWriter out = response.getWriter();
                        ResponseBean responseBean = ResponseBean.sendByCode("you have login failure !", 401);
                        String result = new ObjectMapper().writeValueAsString(responseBean);
                        out.write(result);
                        out.flush();}
                })
               // 和表单登录相干的接口通通都间接通过
                .permitAll()
                .and()
                .logout()
                .logoutUrl("/logout")
                .logoutSuccessHandler(new LogoutSuccessHandler() {
                    @Override
                    public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {response.setContentType("application/json;charset=utf-8");
                        PrintWriter out = response.getWriter();
                        out.write("you have login out success !");
                        out.flush();}
                })
                .permitAll()
                .and()
                .httpBasic()
                .and()
                .csrf().disable();

    }

简略的表单登录配置,这里的 logou 是 Get 申请,若要 Post 申请,则减少一行

logoutRequestMatcher(new AntPathRequestMatcher("/logout","POST"))

and 相当于 ssm 中标签的完结,permitAll 示意登录相干的页面、操作不要拦挡。

  1. 定义明码加密

因为 security 自带盐,用明文加密的都不一样,省去了咱们很多工夫。

    @Bean
    public PasswordEncoder passwordEncoder(){return new BCryptPasswordEncoder();
    }
  1. 引入 JPA 依赖
 <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
 </dependency>
        <!-- jpa -->
  <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
 <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.16.10</version>
 </dependency>
  1. 创立 Use 类
@Data
@Entity(name = "t_user")
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;
    private String username;
    private String password;
    private Integer enabled;
    private Integer locked;
}

  1. 创立 Role 类,为 MyDetail 作筹备
@Data
@Entity(name = "t_role")
public class Role {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;
    private String name;
    private String chineseName;
}

  1. 创立 MyDetail 类,实现 UserDetail
@Data
public class MyUserDetails implements UserDetails {

    private User user;

    private List<Role> roles;

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {List<SimpleGrantedAuthority> authorities = new ArrayList<>();
        if (roles != null && roles.size() > 0) {for (Role role : roles) {authorities.add(new SimpleGrantedAuthority(role.getName()));
            }
        }
        return authorities;
    }

    @Override
    public String getPassword() {return user == null ? null : user.getPassword();
    }

    @Override
    public String getUsername() {return user == null ? null : user.getUsername();
    }

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

    @Override
    public boolean isAccountNonLocked() {Integer locked = user.getLocked();
        if (locked == 0) {return true;}
        return false;
    }

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

    @Override
    public boolean isEnabled() {Integer enabled = user.getEnabled();
        if (enabled == 1) {return true;}
        return false;
    }

    @Override
    public String toString() {
        return "MyUserDetails{" +
                "user=" + user +
                ", roles=" + roles +
                '}';
    }
}
  1. 编写注入实体办法

在测试类中,创建对象,jpa 会主动去创建表格。做一个示范,因为学习,我先创立的表格,你们能够少走弯路了。比方上面这样:

实体,加注解

@Data
@Entity(name = "t_hill_heavy")
public class HillHeavy {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;
    private String username;
    private Boolean handsome;
    private String gender;
    private Integer high;
    private boolean rich;

创立 Dao

public interface HillHeavyDao extends JpaRepository<HillHeavy,Integer> {
    /**
     * 查问
     * @param username 用户名
     * @author 山沉
     * @date 2020/12/28 22:42
     * @return {@link HillHeavy}
     */
    HillHeavy findHillHeavyByUsername(String username);
}

在测试类中:

@SpringBootTest
class EsSearchApplicationTests {private static final Logger logger = LoggerFactory.getLogger(EsSearchApplicationTests.class);

    @Resource
    private HillHeavyDao hillHeavyDao;

    @Test
    void contextLoads() {HillHeavy hillHeavy = new HillHeavy();
        hillHeavy.setUsername("山沉");
        hillHeavy.setHandsome(true);
        hillHeavy.setHigh(180);
        hillHeavy.setGender("男");
        hillHeavy.setRich(true);
        hillHeavyDao.save(hillHeavy);
        logger.info("实体 ----->{}",hillHeavy);
    }

}

这样在用 dao 层去注入实体,在数据库中,也会生成表格,数据。如下:

是有点自恋,啊。原谅想帅的小瘦子。

  1. 有了表构造,在 UserServiceImpl 类,去实现 UserDetailService 类,重写 loadUserByUserName(String username)

在此办法中,从数据库中依据 username,查问出用户,角色,返回 UserDetail 对象。

 @Override
 public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {User user = userMapper.selectUser(username);
     MyUserDetails details = new MyUserDetails();
     if(user == null){throw new BadCredentialsException("this username or password is not true!");
     }
     details.setUser(user);
     Integer id = user.getId();
     List<Role> roles = userMapper.selectRole(id);
     details.setRoles(roles);
     return details;
 }

3. 测试登录

到此,咱们的表单登录,就胜利了。通过 doLogin 登录,携带 user 信息,进入 UsernamePasswordAuthenticationFilter 中,注入用户信息。在从表中取得用户信息与之比照,而后通过登录胜利或失败返回给前端 JSON 格局。

在这里说下,successHandler 是比拟弱小的,在外面能够作重定向,也能够获取用户信息,等等。集成 defaultSuccessUrl() successForwardUrl()

  1. defaultSuccessUrl 能够指定登录胜利的跳转页面,比方输出 welcome/say, 来到 login.html 页面。登录胜利后,会来的 welcome/say
  2. sccessForwardUrl 指定登录胜利后,到那里。不论登录前你操作的哪一个接口,胜利后一律到指定的门路。

测试登录

正文完
 0