日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學(xué)無先后,達(dá)者為師

網(wǎng)站首頁 編程語言 正文

Security前后端分離自定義登錄詳解

作者:為了我的架構(gòu)師 更新時間: 2022-04-17 編程語言

Security前后端分離自定義登錄

思路:

通過自定義接口去處理前端的登錄請求,其主要問題就是如何實現(xiàn)登錄的認(rèn)證!我們需要手動調(diào)用security的認(rèn)證,并且在security配置類中需要定義一些東西

解決:

security配置類(我這里只是測試,根據(jù)個人使用更改即可):

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
        // 查詢用戶信息
        provider.setUserDetailsService(userDetailsService());
        // 設(shè)置密碼加密算法
        provider.setPasswordEncoder(passwordEncoder());
        auth.authenticationProvider(provider);
    }

    @Bean
    @Override
    //構(gòu)建用戶(可以從數(shù)據(jù)庫查找、內(nèi)存模擬,這里為了方便就使用內(nèi)存構(gòu)建)
    protected UserDetailsService userDetailsService() {
        InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
        manager.createUser(User.withUsername("zhangsan").password("123456").authorities("p1").build());
        manager.createUser(User.withUsername("lisi").password("123456").authorities("p2").build());
        return manager;
    }
    @Bean
    //生成密碼編碼類,像MD5,這里使用的這個是直接比較String
    public PasswordEncoder passwordEncoder(){
        return NoOpPasswordEncoder.getInstance();
    }

    @Override
    //security配置,核心
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()
                .authorizeRequests()
                //訪問/test/1,需要p1權(quán)限
                .antMatchers("/test/1").hasAnyAuthority("p1")
                //訪問/test/2,需要p2權(quán)限
                .antMatchers("/test/2").hasAnyAuthority("p2")
                //test下的請求都必須認(rèn)證(登錄)后才能訪問
                .antMatchers("/test/**").authenticated()
                //無條件放行test/** 以外的請求
                .anyRequest().permitAll();
        
    }

    @Override
    @Bean
    public AuthenticationManager authenticationManager() throws Exception {
        return super.authenticationManager();
    }
}

測試接口:

@RestController
public class TestController {
    @Resource
    AuthenticationManager authenticationManager;
    
    @GetMapping("/mylogin")
    public String test(String username, String password){
        //生成驗證令牌
        UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(username,password);
        //獲取驗證完成的認(rèn)證信息
        Authentication authenticate = authenticationManager.authenticate(token);
        //保存到security上下文中
        SecurityContextHolder.getContext().setAuthentication(authenticate);
        return "登錄成功";
    }

    @GetMapping("/test/1")
    public String test1(){
        return "有p1權(quán)限,認(rèn)證后才能看到這條消息";
    }

    @GetMapping("/test/2")
    public String test2(){
        return "有p2權(quán)限,認(rèn)證后才能看到這條消息";
    }
}

詳解:

1.配置類中此方法

image-20211114213750121

為什么需要使用DaoAuthenticationProvider,使用為我們使用用戶名密碼是使用UsernamePasswordAuthenticationToken生成的驗證令牌(登錄接口中也是這樣寫的),而UsernamePasswordAuthenticationToken類型的驗證令牌最終會匹配到DaoAuthenticationProvider來進(jìn)行驗證(因為只有他能驗證這種類型的)。

我們需要給這個驗證提供者(DaoAuthenticationProvider)提供用戶信息和密碼使用什么加密算法。

提供用戶信息即圖中:setUserDetailsService(),其中的userDetailsService()方法是你在配置類中定義的,里面你可以自定定義邏輯,比如最常用的數(shù)據(jù)庫查詢用戶信息

加密算法即圖中:setPasswordEncoder(),其中的passwordEncoder()方法也是在配置類中定義的,稍后會講解那一塊

2.配置類的userDetailsService()方法

image-20211114220730298

這里是在內(nèi)存中創(chuàng)建的數(shù)據(jù),要查數(shù)據(jù)庫怎么玩??(見名知意它是個service,service掉dao就能拿到用戶信息了)

@Override
    @Bean
    protected UserDetailsService userDetailsService() {
        return new UserDetailsServiceImpl();
    }

你需要寫一個類實現(xiàn)UserDetailsService,實現(xiàn)其方法loadUserByUsername(String username)即可,在這個方法里面你就可以調(diào)用dao去查這個用戶,并將其返回(返回類型是userdetails),所以用戶實體類必須繼承User類:如下介紹

是Security中的User類

import org.springframework.security.core.userdetails.User;

這個security中的User,該User實現(xiàn)了UserDetails,所以我們繼承即可。繼承之后我們只需要創(chuàng)建兩個

構(gòu)造函數(shù)即可,它有錯誤提示,點一下就幫我們創(chuàng)建好了:

public class MyUser extends User {
    private String userName;
    private String password;

    public MyUser(String username, String password, Collection authorities) {
        super(username, password, authorities);
    }

    public MyUser(String username, String password, boolean enabled, boolean accountNonExpired, boolean credentialsNonExpired, boolean accountNonLocked, Collection authorities) {
        super(username, password, enabled, accountNonExpired, credentialsNonExpired, accountNonLocked, authorities);
    }
}

3. 密碼加密方式

image-20211114224838212

其作用是選擇一個密碼加密方式,就是在做密碼比對的時候,用什么加密方式去加密前端傳來的密碼,然后再和數(shù)據(jù)庫中的密碼比較!

4.注入AuthenticionManager

image-20211114225130043

就是注入一個認(rèn)證管理器,非要說些什么的話,就說說它是個什么吧。

AuthenticionManager是一個接口,看它的意思就知道它是管理認(rèn)證的,該接口中也只有一個認(rèn)證方法:image-20211114225637875

看看它的實現(xiàn)類image-20211114225713726

其實現(xiàn)類ProviderManager(它是做認(rèn)證的,delegator結(jié)尾的是授權(quán)的。我也不敢確定說對沒有。。)就是我們用到的,它會幫我們找到能夠驗證的認(rèn)證提供類(即DaoAuthenticionProvider)

5.我的登錄接口為啥用的get請求方式

不知道你們注意到我的登錄接口是get請求沒有,是這樣的:

因為我并沒有寫前端,我之前使用的post方式,我圖方便就在postman上測的,能夠登錄成功也確實認(rèn)證成功,但是,并不能訪問需要身份認(rèn)證后才能訪問的請求,我明明已經(jīng)認(rèn)證成功了呀?

是因為,認(rèn)證成功之后,你的認(rèn)證信息會被放到session中

image-20211114231719283

如圖,這是security初始化內(nèi)部實例時(springboot啟動的時候),使用的就是httpsession,你要問在哪用到了這個repo:

image-20211114231921030

我們只需要在接口中,將認(rèn)證信息保存到security上下文即可,后續(xù)就交給security處理:

image-20211114232822236

所以,你必須在同一個瀏覽器中先登錄認(rèn)證才能有這個session,也就才能訪問得到你有權(quán)訪問的請求(當(dāng)然你也可以在postman中加上這個session,不過就麻煩很多,我使用get效果一樣的)

image-20211114233234091

最后這里有一篇不錯的關(guān)于security前后端分離登錄的文章:https://blog.csdn.net/ycf921244819/article/details/108538506

這里是我分析的security認(rèn)證過程源碼(有點亂,但最后兩張圖比較清晰),有興趣的可以來看看:

https://blog.csdn.net/qq_42682745/article/details/120713818

原文鏈接:https://blog.csdn.net/qq_42682745/article/details/121326021

欄目分類
最近更新