spring security實現表單登錄以及自定義URL權限認證

  本文主要介紹怎麼快速搭建一個帶spring security安全認證的應用,其他基礎介紹,基本操作,內容原理略過,着重介紹實現步驟,如需詳細瞭解請閱讀相關文檔。

0.環境

  • jdk 1.8
  • spring boot 
  • MySQL 5

需要準備5張表:

以上爲5張表需要的字段,可根據實際需求變更


1.引入spring security

創建一個spring boot工程,在pom.xml里加入spring security的依賴

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

2.實現表單登錄

不做任何配置的話,spring security採用默認的賬號密碼登錄,賬號user,密碼在項目啓動時會在控制檯打印出來。

按照實際需求我們需要讀取數據庫的用戶進行登錄:

2.1自定義WebSecurityConfigurerAdapter

創建 MySecurityConfig 並且繼承WebSecurityConfigurerAdapter,重寫它的configure(HttpSecurity http)

@EnableWebSecurity
public class MySecurityConfig extends WebSecurityConfigurerAdapter {

 @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .anyRequest().authenticated()//所有請求需登錄
                .and()
                .formLogin()
                .and()
                .logout().logoutUrl("/logout");
    }


}

2.2從數據庫讀取用戶數據

創建一個服務實現UserDetailsService裏的loadUserByUsername即可

@Service
public class UserAuthService implements UserDetailsService {
    @Autowired
    private UserService userService;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        UserEntity userEntity = userService.getByUsername(username);
        if (userEntity == null) {
            throw new UsernameNotFoundException("用戶不存在!");
        }

        return new User(userEntity.getUsername(), userEntity.getPassword(), new ArrayList<>());
    }
}

userService.getByUsername(username);爲根據用戶名從數據庫中讀取用戶信息,自行實現,這裏不做詳細介紹。

把這個服務加入2.1創建的配置裏:

最後MySecurityConfig配置爲:

@EnableWebSecurity
public class MySecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserAuthService userAuthService;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .anyRequest().authenticated()//所有請求需登錄
                .and()
                .formLogin()
                .and()
                .logout().logoutUrl("/logout");
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userAuthService).passwordEncoder(new BCryptPasswordEncoder());
    }
}

spring security需要對密碼進行加密,這裏使用BCryptPasswordEncoder:

String password = new BCryptPasswordEncoder().encode("要加密的密碼");

可以用上面的方式將密碼加密並存入數據庫。

至此,所有配置已完成,啓動項目即可。

2.3自定義登錄頁

啓動項目後,spring security有默認的登錄頁:

如需修改在2.1的配置里加入loginPage即可:

 


3.自定義授權

spring security的權限認證在2.1的configure里加入antMatchers("路徑").需要權限()來實現,它有個access()方法可以自定義表達式來實現權限驗證,因此我們可以寫個方法來實現自己需要的權限驗證。如圖所示:

 

以下爲實現步驟:

3.1將權限信息加入用戶數據裏

在2.2的UserAuthService 獲取到用戶信息後,查詢其擁有的權限,並將允許訪問的url加入用戶信息裏,最後UserAuthService 變爲:

@Service
public class UserAuthService implements UserDetailsService {
    @Autowired
    private UserService userService;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        UserEntity userEntity = userService.getByUsername(username);
        if (userEntity == null) {
            throw new UsernameNotFoundException("用戶不存在!");
        }
        //根據用戶ID獲取其擁有的權限,並將其url加入用戶的權限裏
        List<SimpleGrantedAuthority> permissionList = userService.getPermissionByUserId(userEntity.getId())
        .stream()
        .map(PermissionEntity::getUrl)
        .map(SimpleGrantedAuthority::new)
        .collect(Collectors.toList());
        return new User(userEntity.getUsername(), userEntity.getPassword(), permissionList);
    }
}

userService.getPermissionByUserId(userEntity.getId())爲根據用戶id從數據庫中連表查詢用戶擁有的權限列表,自行實現,這裏不做詳細介紹。

3.2 自定義URL認證方法

之前說過用.access("@authorizeService.check(authentication,request)")來實現,創建一個authorizeService,編寫一個認證方法check(authentication,request),authentication爲用戶的認證信息,request爲請求,在3.1中我們已經將用戶可以訪問的url放入了authentication,因此只要authentication的權限信息裏包含有request請求的url,那麼就認證通過。

@Service("authorizeService")
public class AuthorizeService {

    public boolean check(Authentication authentication, HttpServletRequest request) {
        Object principal = authentication.getPrincipal();
        //判斷是否是認證的用戶
        if (principal != null && principal instanceof UserDetails) {
            UserDetails user = (UserDetails) principal;
            //獲取認證用戶裏的url列表
            Set<SimpleGrantedAuthority> authorities = (Set<SimpleGrantedAuthority>) user.getAuthorities();
            //判斷url列表裏是否包含request請求的url
            boolean contains = authorities.stream()
                    .map(SimpleGrantedAuthority::getAuthority)
                    .anyMatch(request.getRequestURI()::equals);
            return contains;
        }
        return false;
    }
}

 

3.3 配置需要自定義認證的地方

在2.1的configure里加入鏈接.access("@authorizeService.check(authentication,request)")即可,如:

.antMatchers("/admin/**").access("@authorizeService.check(authentication,request)")
.anyRequest().access("@authorizeService.check(authentication,request)")

 

至此,所有的配置已完成。


源碼:https://github.com/fi00wind/spring-security-demo

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章