springboot學習之授權Spring Security


SpringSecurity核心功能:認證、授權、攻擊防護(防止偽造身份)

涉及的依賴如下:

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>
 
        

  



新建一個項目,添加如上依賴【添加依賴之后默認開始授權驗證】,在控制器controller中測試,指定url,比如
@Controller
public class UserController {

    @RequestMapping(value="/hello")
    @ResponseBody
    public String hello(){return "=======Welcome to HelloWorld==============";}
}

  

如上,原本啟動項目后,在地址欄中輸入http://localhost:8080/hello應該顯示返回的內容

然而此次加了安全驗證后,不管url中訪問的地址是什么,hello還是hello111,均返回login頁面,如下

 

此時系統都沒有連DB,用戶名和密碼是什么?

控制台中有消息,比如Using generated security password: 76dade1c-f190-44f8-915c-7a6b6917fb9a【每次隨機生成的密碼】

將用戶名 user 和 密碼 76dade1c-f190-44f8-915c-7a6b6917fb9a 填入上面對話框中,點擊按鈕Sign in

 

 若之前訪問的頁面是控制器中配置的頁面http://localhost:8080/hello

則此時能成功顯示

若之前訪問的頁面是其他的,控制器中未配置的,則重定向后返回頁面不存在。

 

當前自己的項目中,總不能用系統生成的密碼進行登錄獲得權限,那不要被別人笑死。

 

進階階段:

我簡單創建了一張表,希望該表的人輸入匹配的用戶名和密碼后,方能登錄。

CREATE TABLE `admin_user`(
`id` int(4) NOT NULL AUTO_INCREMENT,
`username` VARCHAR(100),
`password` VARCHAR(100),
`role` VARCHAR(100),
`realname` VARCHAR(100),
`mobile` VARCHAR(2000),
`state` BIT default 0,
`info` VARCHAR(200),
PRIMARY KEY (`id`)
)ENGINE=InnoDB AUTO_INCREMENT=300;

  塞了幾條數據進去,然后我希望用戶在頁面上進行登錄,那我必須還要創建一個User對象,所謂登錄就是傳入username和password匹配的場景,只要匹配,就登錄成功,跳轉到之前的url

public class User {

    private int id;
    private String name;
    private String password; 省略 getter and setter}

  

public interface UserService {

    User login(String name, String password);
}

  

@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Override
    public User login(String name, String password) {
        String sql ="select * from admin_user where username =? and password = ?";
        User user =jdbcTemplate.queryForObject(sql,new UserRowMapper(),name,password);
        return user;

    }
}

  

public class UserRowMapper implements RowMapper<User> {
    @Override
    public User mapRow(ResultSet resultSet, int i) throws SQLException {
        //此處要使用表中的字段,不能使用屬性
        int id =resultSet.getInt("id");
        String username = resultSet.getString("username");
        String password = resultSet.getString("password");
        //String role = resultSet.getString("role");

        User user = new User();
        user.setId(id);
        user.setName(username);
        user.setPassword(password);

        return user;
    }
}

  

登錄的方法啪啪啪很快就寫好了,我要怎么讓系統知道,所有的請求,要先進行登錄呢,登錄的URL是什么?

 

先看看別人的代碼,貌似是實現了UserDetailsService 接口,而點進去發現該接口就一個方法

package org.springframework.security.core.userdetails;

public interface UserDetailsService {
    UserDetails loadUserByUsername(String var1) throws UsernameNotFoundException;
}

  通過一個String類型的變量val1,獲取用戶的詳細信息。。。怎么跟我想的不太一樣?

再點進去發現UserDetails 也是一個接口

package org.springframework.security.core.userdetails;

import java.io.Serializable;
import java.util.Collection;
import org.springframework.security.core.GrantedAuthority;

public interface UserDetails extends Serializable {
    Collection<? extends GrantedAuthority> getAuthorities();

    String getPassword();

    String getUsername();

    boolean isAccountNonExpired();

    boolean isAccountNonLocked();

    boolean isCredentialsNonExpired();

    boolean isEnabled();
}

 一個集合,收集權限,結合做過的項目,有的權限是超級管理員,有的權限是普通管理員,又或者有的刪,有新增,有更新等等權限;兩個返回String的方法;

還有判斷賬戶是否過期,被鎖,驗證是否過期,是否開啟了。。。

 

 看來光看別人的代碼,還是丈二和尚摸不着頭腦呢,去看看官方文檔吧

 

https://spring.io/projects/spring-security

https://spring.io/guides/topicals/spring-security-architecture

 

英文原文我就不粘貼了,翻譯過來,大意就是:

應用程序權限歸結於兩個獨立的問題:

1. 你是誰

2. 你有什么樣的權限

一般叫法是權限控制 或者 授權

 

下面開始講框架中的源碼,通過看源碼可以了解設計的思路

1. 授權策略中主要的接口是AuthenticationManager,並且只有一個方法

public interface AuthenticationManager {

  Authentication authenticate(Authentication authentication)
    throws AuthenticationException;

} 

 驗證管理員在方法authenticate()可以做三件事

a. 輸入的信息是有效的當事人,驗證通過,返回Authentication 

b. 輸入的信息是無效的當事人,驗證不通過,返回AuthenticationException 

c. 無法判斷的時候,返回一個null

看到這兒,就覺得我想通過查詢 用戶名 = 輸入的用戶名 且 密碼 =輸入密碼的想法真是異想天開了。

 

 

Filter Chains,過濾鏈,默認對所有的范文url進行過濾,意味着打開這個網站的任何鏈接,都彈出授權頁面

而如果像如下的例子,則可以在foo下的下url不進行授權驗證,說白了,不登錄,這個url下也可以訪問。 想想日常使用場景,比如總要有個注冊頁面吧,不能全面鏈接都要求登錄。不注冊如何登錄呢?

@Configuration
@Order(SecurityProperties.BASIC_AUTH_ORDER - 10)
public class ApplicationConfigurerAdapter extends WebSecurityConfigurerAdapter {
  @Override
  protected void configure(HttpSecurity http) throws Exception {
    http.antMatcher("/foo/**")
     ...;
  }
}

  

 

用戶登錄了之后,要怎么查看個人信息,傳入@AuthenticationPrincipal,當事人對象Principal principal

@RequestMapping("/foo")
public String foo(@AuthenticationPrincipal User user) {
  ... // do stuff with user
}

 

@RequestMapping("/foo")
public String foo(Principal principal) {
  Authentication authentication = (Authentication) principal;
  User = (User) authentication.getPrincipal();
  ... // do stuff with user
}

  

 使用規則介紹完了,花了兩天把授權一個可用的項目的代碼整理出來,貼上github路徑

https://github.com/JasmineQian/buglist

 

其中用的是springboot 2.1.2 Realease 版本,和以前的版本稍微有一點區別,比如必須對密碼加密校驗,So存進去的密碼處,必須加密之后存入數據庫

<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.2.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>


程序中驗證的用戶名和密碼

自己建一張表,叫做qa_user,添加如下數據
2 admin $2a$10$A4EZrzoXqj4mVyXiw/fsp.mJ.Ne5aVAMWrMK0mAb2zY7lJ/H6Jryi admin ROLE_USER,ROLE_ADMIN

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM