SpringSecurity(1)---認證+受權代碼實現

認證+受權代碼實現

Spring Security是 一種基於 Spring AOP 和 Servlet 過濾器的安全框架。它提供全面的安全性解決方案,同時在 Web 請求級和方法調用級處理身份確認和受權。html

有關認證和受權的理論知識,以前有寫過相關博客。瞭解權限管理java

1、SpringSceurity工做流程

網上找一張圖,以爲畫的挺好的,比較容易理解。否則換的是源碼流程圖很難去理解。git

圖片地址 : 地址 能夠單機放大看更加清楚github

要想理解這張圖建議看下這篇博客,由於這張圖中須要自定義的My...類,在文章中都有說明,因此更好理解點。web

Spring Boot Security 詳解spring


2、認證+受權代碼

這裏只展現一些核心代碼,具體完整代碼放在github上。數據庫

一、UserDetails接口

Security 中的用戶接口,咱們自定義用戶類要實現該接口, 用於向security中注入當前用戶的姓名密碼,和擁有的角色。同時也包含一些其它信息,好比當前用戶是否過時,安全

帳號是否鎖定等等。app

本身定義User實現這個接口框架

public class User implements UserDetails {
    private String username;
    private String password;
    private List<Role> roles;
    /**
     * 獲取用戶名
     */
    @Override
    public String getUsername() {
        return username;
    }
    /**
     * 獲取密碼
     */
    @Override
    public String getPassword() {
        return password;
    }
    /**
     * 用戶的權限集, 默認須要添加ROLE_ 前綴
     */
    @Override
    @JsonIgnore
    public List<GrantedAuthority> getAuthorities() {
        List<GrantedAuthority> authorities = new ArrayList<>();
        for (Role role : roles) {
            authorities.add(new SimpleGrantedAuthority("ROLE_" + role.getName()));
        }
        return authorities;
    }
    /**
     * 帳戶是否過時
     */
    @Override
    @JsonIgnore
    public boolean isAccountNonExpired() {
        return true;
    }
    /**
     * 帳戶是否鎖定
     */
    @Override
    @JsonIgnore
    public boolean isAccountNonLocked() {
        return true;
    }
    /**
     * 憑證是否過時
     */
    @Override
    @JsonIgnore
    public boolean isCredentialsNonExpired() {
        return true;
    }
    /**
     * 用戶是否可用
     */
    @Override
    public boolean isEnabled() {
        return true;
    }  
}

二、UserDetailsService

Security 中的用戶 Service,自定義用戶服務類須要實現該接口。這個接口只有一個方法須要咱們去實現,那就是經過用戶名去獲取用戶信息。這裏也是和數據庫交互獲取

用戶認證和受權信息的地方。

@Service
@Slf4j
public class UserService implements UserDetailsService {

    @Override
    public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException {
        //TODO 正常應該查詢數據庫獲取用戶和用戶的權限
//        User user = userMapper.loadUserByUsername(userName);
//        List<Role> roles = rolesMapper.getRolesByUid(user.getId());
//        user.setRoles(roles);
        log.info("登錄用戶名: {}", userName);
        //經過用戶名查詢到的密碼 密碼確定是加密過的 這裏明文密碼是 123456
        String password = "e10adc3949ba59abbe56e057f20f883e";
        //用戶對應權限
        List<Role> roles = Lists.newArrayList(new Role(1L, "教師"), new Role(2L, "學生"));
        User user = new User(userName, password, roles);
        return user;
    }
}

注意 這裏的明文密碼是 123456,也就是用戶輸入這個才能完成認證。受權的話當前用戶有兩個角色 教師學生。在下面測試的時候會用到。

三、WebSecurityConfigurerAdapter

它是Spring Security的Java 配置類。建立類SecurityConfiguration繼承 WebSecurityConfigurerAdapter,來對咱們應用中全部的安全相關的事項(

全部url,驗證用戶名密碼,表單重定向等)進行控制。

@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    /**
     * 一、配置的是認證信息, AuthenticationManagerBuilder 這個類,就是AuthenticationManager的建造者, 咱們只須要向這個類中, 配置用戶信息,
     *    就能生成對應的AuthenticationManager, 這個類也提過,是用戶身份的管理者, 是認證的入口, 所以,咱們須要經過這個配置,想security提供真實的用戶身份。
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    }
    /**
     * 二、配置Security的認證策略, 每一個模塊配置使用and結尾。這個也是最複雜的
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
    }
    /**
     * 三、這個配置方法用於配置靜態資源的處理方式,可以使用 Ant 匹配規則。就是能夠不用認證就能夠直接訪問的接口
     */
    @Override
    public void configure(WebSecurity web) throws Exception {
    }
}

完整示例

@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserService userService;
    /**
     * 密碼驗證器
     */
    @Autowired
    private PassWordEncorder passWordEncorder;
    /**
     * 成功處理器
     */
    @Autowired
    private AuthenctiationSuccessHandler authenctiationSuccessHandler;

    /**
     * 失敗處理器
     */
   @Autowired
   private AuthenctiationFailHandler authenctiationFailHandler;
   /**
    * 向Security注入用戶信息
    */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userService).passwordEncoder(passWordEncorder);
    }
    /**
     * 配置規則
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //開啓登錄配置
        http.authorizeRequests()
                // 登陸以後就能訪問
                .antMatchers("/no-authorize").authenticated()
                // 登錄後 須要校長角色權限
                .antMatchers("/need-authorize").hasRole("校長")
                // 其餘的路徑都是登陸後便可訪問
                .anyRequest().authenticated()
                .and().formLogin()
                // 定義登陸頁面,未登陸時,訪問一個須要登陸以後才能訪問的接口,會自動跳轉到該頁面
                .loginPage("/login_page")
                //登陸成功的處理器
                .successHandler(authenctiationSuccessHandler)
                //登陸失敗的處理器
                .failureHandler(authenctiationFailHandler)
                // 登陸處理接口
                .loginProcessingUrl("/login")
                // 定義登陸時,用戶名的 key,默認爲 username
                .usernameParameter("username")
                //定義登陸時,用戶密碼的 key,默認爲 password
                .passwordParameter("password").permitAll()
                .and().logout()
                ////和表單登陸相關的接口通通都直接經過
                .permitAll()
                .and().csrf().disable().exceptionHandling().accessDeniedHandler(getAccessDeniedHandler());
    }

    /**
     * 對於/static/  下的路徑都不用認證
     */
    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/no-login");
    }

    /**
     * 用戶未認證異常攔截
     */
    @Bean
    AccessDeniedHandler getAccessDeniedHandler() {
        return new AuthenticationAccessDeniedHandler();
    }
}

注意 這裏一共配置了三個路徑用於測試。

一、/no-login 接口不須要認證就能夠直接訪問
二、/no-authorize 須要認證 但不須要受權就能夠訪問
三、/need-authorize 首先須要認證 認證經過還須要受權 這裏須要校長的角色才能夠訪問該接口 可是咱們測試用戶只有教師和學生因此沒有權限訪問該接口

下面會針對這個個接口分別進行測試。


3、測試

一、接口提供

@RestController
public class TestController {

    /**
     * 一、不須要登錄就能夠訪問
     */
    @RequestMapping(value = "/no-login")
    public ServiceResponse noLogin() {
        return ServiceResponse.success("歡迎訪問不須要登錄接口");
    }
    /**
     * 二、只登錄,不準認證接口
     */
    @RequestMapping(value = "/no-authorize")
    public ServiceResponse needAuthorize(){
        return ServiceResponse.success("登錄了 不用受權");
    }
    /**
     * 三、登錄 + 相關認證接口
     */
    @RequestMapping(value = "/need-authorize")
    public ServiceResponse noAuthorize() {
        return ServiceResponse.success("登錄+受權成功");
    }
    /**
     * @Description: 若是自動跳轉到這個頁面,說明用戶未登陸,返回相應的提示便可
     */
    @RequestMapping("/login_page")
    public ServiceResponse loginPage() {
        return  ServiceResponse.failure("001", "還沒有登陸,請登陸!");
    }
}

二、未登陸訪問 no-login 和 no-authorize 接口

no-login接口

很明顯沒有登錄 請求該接口成功!

no-authorize接口

沒有登錄訪問失敗,在上面配置了若是用戶沒有認證的話跳轉到login_page接口,因此這裏返回 '還沒有登陸,請登陸!'

三、登錄後訪問 no-authorize 和 need-authorize 接口

先登錄

根據上面配置登錄的路徑爲 /login 請求參數包括 usernamepassword

注意 這裏須要post請求。

no-authorize 接口

登錄就能夠訪問了。

need-authorize 接口

雖然登錄成功了,可是由於該接口須要校長角色,以前給該用戶只配置了教師和學生的角色因此訪問失敗。


參考

一、SpringSide 3 中的安全框架

二、Spring Security 工做原理概覽

三、Spring Boot Security 詳解 很贊



別人罵我胖,我會生氣,由於我內心認可了我胖。別人說我矮,我就會以爲可笑,由於我內心知道我不可能矮。這就是咱們爲何會對別人的攻擊生氣。
攻我盾者,乃我心裏之矛(17)
相關文章
相關標籤/搜索