spring-boot 整合 spring-security

東方柏發表於2018-07-14
  1. 引入相關包;
  2. 配置程式碼(SecurityConfig ,UserDetailsServiceImpl ,UserSecurity )
  3. 重點:
    1. config 配置 hasRole ("ADMIN")一定要在 authenticated 前面,也就是說配置規則遵從從上往下的順序
    2. request.getRequestDispatcher(newUrl).forward(request, response)跳轉之後不會進入後續攔截器,也就是說不會被security管理了。
  4. 程式碼參考
@EnableAutoConfiguration
@ComponentScan
@EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserDetailsService userDetailsService;

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    /**
     * 目前只供測試用例使用
     * 模擬 UserDetailsService 驗證,便於許可權測試直接使用@WithUserDetails(@MockWidthUser需要指定使用者名稱和密碼)
     */
     @Bean
     public UserDetailsService userDetailsService() {
         UserDetails userDetails = (UserDetails) new User("admin", "abc123456",
         AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_ADMIN"));//授予 admin角色
         return new InMemoryUserDetailsManager(Arrays.asList(userDetails));
     }

    /**
     * 使用者認證,主要是根據使用者名稱獲取使用者角色、許可權,來匹配使用者登入和使用者是否有許可權操作
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService);
    }

    /**
     * 訪問許可權過濾
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // We recommend disabling CSRF protection completely only if you are creating a
        // service that is used by non-browser clients
        // 以此支援非瀏覽器 post 訪問 shutdown
        http.csrf().disable();
        // 新增自定義過濾器,額外處理
        http.addFilterBefore(new RouterFilter(), AnonymousAuthenticationFilter.class);
        http.authorizeRequests()
                .antMatchers("/assets/**", "/**/*.*", "/mocksession/**",
                "/session/weixin", "/session/github").permitAll()
                // 安全關閉服務介面,擁有 ADMIN 許可權的使用者可以訪問該 rul
                .antMatchers("/actuator/shutdown").hasRole("ADMIN")
                .antMatchers("/app/redeploy").hasRole("ADMIN")
                .anyRequest().authenticated() // 任何請求,登入後可以訪問
                .and()
                    .formLogin()
                    .loginPage("/")
                    .permitAll()
                // 開啟basic認證,若不新增此項,將不能通過curl的basic方式傳遞使用者資訊
                .and()
                    .httpBasic()
                .and()
                // 重定向url由預設值/login?logout改為/
                    .logout()
                        .logoutSuccessUrl("/")
                        .permitAll()
                        .invalidateHttpSession(true);
    }

}

UserDetailsServiceImpl 實現

@Component
public class UserDetailsServiceImpl implements UserDetailsService {

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Autowired
    private UserService userService;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        UserInfo userInfo = userService.getByLoginName(username);
        if (userInfo == null) {
            throw new UsernameNotFoundException(username + " 不存在!");
        }
        // 加密密碼
         String encode = passwordEncoder.encode(UserSecurity.getInternalPassword());
        if (userInfo.isAdmin()) {
            return new User(username, encode, AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_ADMIN"));
        } else {
            return new User(username, encode, AuthorityUtils.commaSeparatedStringToAuthorityList(""));
        }
    }

}

整合使用者自定義登入session,轉接到security,使用如下工具類setUser

public class UserSecurity {

    public static void setUser(UserInfo userInfo) {
        UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(userInfo.getLoginName(), getInternalPassword());
        SecurityContextHolder.getContext().setAuthentication(authRequest);
    }

    public static String getInternalPassword() {
        return "abc123456";
    }
}

相關文章