天天看點

spring boot 內建cas單點登入1 application.properties

整理 spring boot cas ,學習spring boot cas

1 application.properties

#CAS服務位址http://xxx.xxx.xx.xx:8080
cas.server.host.url=http://xxx.xxx.xx.xx:8080
#CAS服務登入位址
cas.server.host.login_url=${cas.server.host.url}/login
#CAS服務登出位址
cas.server.host.logout_url=${cas.server.host.url}/logout?service=${app.server.host.url}
#應用通路位址
app.server.host.url=http://localhost:8085
#應用登入位址
app.login.url=/cas
#應用登出位址
app.logout.url=/logout      

2 讀取application.properties

@Component
public class MyCasProperties {
    @Value("${cas.server.host.url}")
    private String casServerUrl;
    @Value("${cas.server.host.login_url}")
    private String casServerLoginUrl;
    @Value("${cas.server.host.logout_url}")
    private String casServerLogoutUrl;
    @Value("${app.server.host.url}")
    private String appServerUrl;
    @Value("${app.login.url}")
    private String appLoginUrl;
    @Value("${app.logout.url}")
    private String appLogoutUrl;
    public String getCasServerUrl() {
        return casServerUrl;
    }
    public void setCasServerUrl(String casServerUrl) {
        this.casServerUrl = casServerUrl;
    }
    public String getCasServerLoginUrl() {
        return casServerLoginUrl;
    }
    public void setCasServerLoginUrl(String casServerLoginUrl) {
        this.casServerLoginUrl = casServerLoginUrl;
    }
    public String getCasServerLogoutUrl() {
        return casServerLogoutUrl;
    }
    public void setCasServerLogoutUrl(String casServerLogoutUrl) {
        this.casServerLogoutUrl = casServerLogoutUrl;
    }
    public String getAppServerUrl() {
        return appServerUrl;
    }
    public void setAppServerUrl(String appServerUrl) {
        this.appServerUrl = appServerUrl;
    }
    public String getAppLoginUrl() {
        return appLoginUrl;
    }
    public void setAppLoginUrl(String appLoginUrl) {
        this.appLoginUrl = appLoginUrl;
    }
    public String getAppLogoutUrl() {
        return appLogoutUrl;
    }
    public void setAppLogoutUrl(String appLogoutUrl) {
        this.appLogoutUrl = appLogoutUrl;
    }
}
      

 3 啟用web權限 WebSecurityConfigurerAdapter

@Configuration
@EnableWebSecurity//啟用web權限
public class MyWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
    @Autowired
    private MyCasProperties myCasProperties;
    @Autowired
    MyMetadataSourceService mySecurityMetadataSource;
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        super.configure(auth);
        auth.authenticationProvider(casAuthenticationProvider());
    }
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .anyRequest().authenticated().and()
                .logout().permitAll().and().formLogin();

        http.exceptionHandling().authenticationEntryPoint(casAuthenticationEntryPoint())
                .and().addFilter(casAuthenticationFilter()).addFilterBefore(casLogoutFilter(), LogoutFilter.class)
                .addFilterBefore(singleSignOutFilter(), CasAuthenticationFilter.class);

         
        FilterSecurityInterceptor filterSecurityInterceptor =
                new FilterSecurityInterceptor();

        filterSecurityInterceptor.setSecurityMetadataSource(mySecurityMetadataSource);
        filterSecurityInterceptor.setAccessDecisionManager(accessDecisionManager());
        filterSecurityInterceptor.setAuthenticationManager(authenticationManagerBean());

         
        http.addFilterAt(filterSecurityInterceptor, FilterSecurityInterceptor.class);

        http.csrf().disable(); //禁用CSRF
    }

    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("cas/**");
    }

    @Bean(name = "accessDecisionManager")
    public AccessDecisionManager accessDecisionManager() {
        List<AccessDecisionVoter<? extends Object>> decisionVoters = new ArrayList();
        decisionVoters.add(new AuthenticatedVoter());
        MyAccessDecisionManager accessDecisionManager = new MyAccessDecisionManager(decisionVoters);
        return accessDecisionManager;
    }

    @Bean
    public CasAuthenticationEntryPoint casAuthenticationEntryPoint() {
        CasAuthenticationEntryPoint casAuthenticationEntryPoint = new CasAuthenticationEntryPoint();
        casAuthenticationEntryPoint.setLoginUrl(myCasProperties.getCasServerLoginUrl());
        casAuthenticationEntryPoint.setServiceProperties(serviceProperties());
        return casAuthenticationEntryPoint;
    }

    /**
     * 指定service相關資訊
     */
    @Bean
    public ServiceProperties serviceProperties() {
        ServiceProperties serviceProperties = new ServiceProperties();
        serviceProperties.setService(myCasProperties.getAppServerUrl() + myCasProperties.getAppLoginUrl());
        serviceProperties.setAuthenticateAllArtifacts(true);
        return serviceProperties;
    }

    /**
     * CAS認證過濾器
     */
    @Bean
    public CasAuthenticationFilter casAuthenticationFilter() throws Exception {
        CasAuthenticationFilter casAuthenticationFilter = new CasAuthenticationFilter();
        casAuthenticationFilter.setAuthenticationManager(authenticationManager());
        casAuthenticationFilter.setFilterProcessesUrl(myCasProperties.getAppLoginUrl());
        return casAuthenticationFilter;
    }

    @Bean
    public CasAuthenticationProvider casAuthenticationProvider() {
        CasAuthenticationProvider casAuthenticationProvider = new CasAuthenticationProvider();
        casAuthenticationProvider.setAuthenticationUserDetailsService(customUserDetailsService());
        casAuthenticationProvider.setServiceProperties(serviceProperties());
        casAuthenticationProvider.setTicketValidator(cas20ServiceTicketValidator());
        casAuthenticationProvider.setKey("casProvider");
        return casAuthenticationProvider;
    }


    /**
     * 使用者自定義的AuthenticationUserDetailsService
     */
    @Bean
    public AuthenticationUserDetailsService<CasAssertionAuthenticationToken> customUserDetailsService() {
        return new CustomUserDetailsService();
    }


    @Bean
    public Cas20ServiceTicketValidator cas20ServiceTicketValidator() {
        return new Cas20ServiceTicketValidator(myCasProperties.getCasServerUrl());
    }


    /**
     * 單點登出過濾器
     */
    @Bean
    public SingleSignOutFilter singleSignOutFilter() {
        SingleSignOutFilter singleSignOutFilter = new SingleSignOutFilter();
        singleSignOutFilter.setCasServerUrlPrefix(myCasProperties.getCasServerUrl());
        singleSignOutFilter.setIgnoreInitConfiguration(true);
        return singleSignOutFilter;
    }

    /**
     * 請求單點退出過濾器
     */
    @Bean
    public LogoutFilter casLogoutFilter() {
        LogoutFilter logoutFilter = new LogoutFilter(myCasProperties.getCasServerLogoutUrl(), new SecurityContextLogoutHandler());
        logoutFilter.setFilterProcessesUrl(myCasProperties.getAppLogoutUrl());
        return logoutFilter;
    }      

4 登入使用者資訊儲存

public class MyUserDetails implements UserDetails {
    private List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return authorities;
    }

    @Override
    public String getPassword() {
        return "xxx";
    }

    @Override
    public String getUsername() {
        return "xxx";
    }

    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }

    @Override
    public boolean isEnabled() {
        return true;
    }

    public void setAuthorities(List<GrantedAuthority> authorities) {
        this.authorities = authorities;
    }
}
      

5 加載現有資源 url

@Service
public class MyMetadataSourceService implements
        FilterInvocationSecurityMetadataSource {

    /**
     * 加載權限表中所有權限
     */
    public Map loadResourceDefine() {

        Map map = new HashMap();
        List<String> ls = new ArrayList<>();

        ls.add("/");
        ls.add("/hello");
        ls.add("/authorize");
        ls.add("/error");

        for (String s : ls) {
            ArrayList array = new ArrayList<>();
            array.add(new SecurityConfig(s));
            map.put(s, array);
        }
        return map;

    }

    /**
     * 在權限中的會執行  decide
     *
     * @param object xx
     * @return xx
     * @throws IllegalArgumentException xx
     */
    @Override
    public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException {


        Map<String, Collection<ConfigAttribute>> map = loadResourceDefine();

        HttpServletRequest request = ((FilterInvocation) object).getHttpRequest();
        AntPathRequestMatcher matcher;
        String resUrl;

        for (Iterator<Map.Entry<String, Collection<ConfigAttribute>>> iter = map.entrySet().iterator(); iter.hasNext(); ) {
            Map.Entry<String, Collection<ConfigAttribute>> me = iter.next();
            resUrl = me.getKey();
            matcher = new AntPathRequestMatcher(resUrl);
            if (matcher.matches(request)) {
                return me.getValue();
            }
        }
        return SecurityConfig.createList("YOU_NEED_PORM");

    }

    @Override
    public Collection<ConfigAttribute> getAllConfigAttributes() {
        return null;
    }

    @Override
    public boolean supports(Class<?> clazz) {
        return true;
    }

}      

6控制 是不是讓進入系統

public class MyAccessDecisionManager extends AbstractAccessDecisionManager {


    public MyAccessDecisionManager(List<AccessDecisionVoter<? extends Object>> decisionVoters) {
        super(decisionVoters);
    }


    /**
     * @param authentication   UserService 權限資訊集合
     * @param object           equset message
     * @param configAttributes MyMetadataSourceService
     * @throws AccessDeniedException,InsufficientAuthenticationException,BadCredentialsException 加入權限表後,則傳回給 decide 方法 其它情況 不做控制
     */
    @Override
    public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes)
            throws AccessDeniedException, InsufficientAuthenticationException, BadCredentialsException, DisabledException {


        if (authentication instanceof AnonymousAuthenticationToken) {
            throw new BadCredentialsException("未登入");
        }

        if (null == configAttributes || configAttributes.size() == 0) {
            return;
        }

        for (Iterator<ConfigAttribute> iter = configAttributes.iterator(); iter.hasNext(); ) {
            ConfigAttribute configAttribute = iter.next();
            String permcode = configAttribute.getAttribute();
            if ("YOU_NEED_PORM".equals(permcode)) {
                throw new AccessDeniedException("no perm");
            }

            for (GrantedAuthority ga : authentication.getAuthorities()) {
                if (permcode.trim().equals(ga.getAuthority())) {
                    return;
                }
            }
        }


        throw new AccessDeniedException("no perm");
    }

    @Override
    public boolean supports(ConfigAttribute attribute) {
        return true;
    }

    @Override
    public boolean supports(Class<?> clazz) {
        return true;
    }
}      

7 目前登入使用者所擁有的權限

public class CustomUserDetailsService implements AuthenticationUserDetailsService {


    @Override
    public UserDetails loadUserDetails(Authentication authentication) throws UsernameNotFoundException {
        System.out.println("目前的使用者名是:" + authentication.getName());
        /*這裡我為了友善,就直接傳回一個使用者資訊,實際當中這裡修改為查詢資料庫或者調用服務什麼的來擷取使用者資訊*/
        MyUserDetails userInfo = new MyUserDetails();
        List<GrantedAuthority> grantedAuthorities = new ArrayList<>();
        GrantedAuthority grantedAuthority = new SimpleGrantedAuthority("/");
        GrantedAuthority grantedAuthority2 = new SimpleGrantedAuthority("/hello");
        GrantedAuthority grantedAuthority3 = new SimpleGrantedAuthority("/authorize");
        GrantedAuthority grantedAuthority4 = new SimpleGrantedAuthority("/error");

        grantedAuthorities.add(grantedAuthority);
        grantedAuthorities.add(grantedAuthority2);
        grantedAuthorities.add(grantedAuthority3);
        grantedAuthorities.add(grantedAuthority4);
        userInfo.setAuthorities(grantedAuthorities);
        return userInfo;
    }
}
      

8測試權限攔截的正确性

@RequestMapping("/")
public String index() {
    return "index success";
}

@RequestMapping("/hello")
public String hello() {
    return "hello welcome sso";
}

@RequestMapping("/security")
public String security() {
    return "security";
}

@RequestMapping("/authorize")
public String authorize() {
    return "安全驗證";

}      

繼續閱讀