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
@Datapublic 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);}

在测试类中:

@SpringBootTestclass 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 指定登录胜利后,到那里。不论登录前你操作的哪一个接口,胜利后一律到指定的门路。

测试登录