天天看點

spring-boot 整合 spring-security

  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";
    }
}
           

繼續閱讀