Spring Security 之學習路途

Spring Security 學習之旅開端

SpringSecurity 開始

項目:Githubhtml

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,能夠定義忽略路徑java

@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請求,則增長一行
git

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

and至關於ssm中標籤的結束,permitAll表示登陸相關的頁面、操做不要攔截。github

  1. 定義密碼加密

因爲security自帶鹽,用明文加密的都不同,省去了咱們不少時間。web

@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會自動去建立表格。作一個示範,因爲學習,我先建立的表格,大家能夠少走彎路了。好比下面這樣:

實體,加註解
spring

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

在測試類中:
json

@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層去注入實體,在數據庫中,也會生成表格,數據。以下:
app

是有點自戀,啊。原諒想帥的小胖子。

  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 指定登陸成功後,到那裏。無論登陸前你操做的哪個接口,成功後一概到指定的路徑。

測試登陸

相關文章
相關標籤/搜索