이 글은 CAS 통합을 위해 Spring 보안을 사용하는 Spring Boot에 대한 자세한 설명을 주로 소개하며, 관심 있는 친구들은 참고하시기 바랍니다
1. 프로젝트 만들기
Maven 프로젝트 생성: springboot-security-cas
2. 종속성 추가
프로젝트 생성 후, pom.xml을 열고 pom.xml에 다음 콘텐츠를 추가합니다.
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.4.3.RELEASE</version> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- security starter Poms --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <!-- security 对CAS支持 --> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-cas</artifactId> </dependency> <!-- security taglibs --> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-taglibs</artifactId> </dependency> <!-- 热加载 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> <optional>true</optional> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build>
3. application.properties 생성
애플리케이션 생성 .properties 파일에 다음 내용을 추가합니다:
#CAS服务地址 cas.server.host.url=http://localhost:8081/cas #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:8080 #应用登录地址 app.login.url=/login #应用登出地址 app.logout.url=/logout
4. 입구 시작 클래스(MainConfig)를 생성합니다.
입구 시작 클래스 MainConfig를 만듭니다.
package com.chengli.springboot; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @SpringBootApplication public class MainConfig { public static void main(String[] args) { SpringApplication.run(MainConfig.class, args); } @RequestMapping("/") public String index() { return "访问了首页哦"; } @RequestMapping("/hello") public String hello() { return "不验证哦"; } @PreAuthorize("hasAuthority('TEST')")//有TEST权限的才能访问 @RequestMapping("/security") public String security() { return "hello world security"; } @PreAuthorize("hasAuthority('ADMIN')")//必须要有ADMIN权限的才能访问 @RequestMapping("/authorize") public String authorize() { return "有权限访问"; } /**这里注意的是,TEST与ADMIN只是权限编码,可以自己定义一套规则,根据实际情况即可*/ }
5. 보안 구성 클래스(SecurityConfig)를 생성합니다.
보안 구성 클래스 SecurityConfig를 생성합니다. :
package com.chengli.springboot.security; import org.jasig.cas.client.session.SingleSignOutFilter; import org.jasig.cas.client.validation.Cas20ServiceTicketValidator; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.cas.ServiceProperties; import org.springframework.security.cas.authentication.CasAssertionAuthenticationToken; import org.springframework.security.cas.authentication.CasAuthenticationProvider; import org.springframework.security.cas.web.CasAuthenticationEntryPoint; import org.springframework.security.cas.web.CasAuthenticationFilter; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.core.userdetails.AuthenticationUserDetailsService; import org.springframework.security.web.authentication.logout.LogoutFilter; import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler; import com.chengli.springboot.custom.CustomUserDetailsService; import com.chengli.springboot.properties.CasProperties; @Configuration @EnableWebSecurity //启用web权限 @EnableGlobalMethodSecurity(prePostEnabled = true) //启用方法验证 public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private CasProperties casProperties; /**定义认证用户信息获取来源,密码校验规则等*/ @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { super.configure(auth); auth.authenticationProvider(casAuthenticationProvider()); //inMemoryAuthentication 从内存中获取 //auth.inMemoryAuthentication().withUser("chengli").password("123456").roles("USER") //.and().withUser("admin").password("123456").roles("ADMIN"); //jdbcAuthentication从数据库中获取,但是默认是以security提供的表结构 //usersByUsernameQuery 指定查询用户SQL //authoritiesByUsernameQuery 指定查询权限SQL //auth.jdbcAuthentication().dataSource(dataSource).usersByUsernameQuery(query).authoritiesByUsernameQuery(query); //注入userDetailsService,需要实现userDetailsService接口 //auth.userDetailsService(userDetailsService); } /**定义安全策略*/ @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests()//配置安全策略 //.antMatchers("/","/hello").permitAll()//定义/请求不需要验证 .anyRequest().authenticated()//其余的所有请求都需要验证 .and() .logout() .permitAll()//定义logout不需要验证 .and() .formLogin();//使用form表单登录 http.exceptionHandling().authenticationEntryPoint(casAuthenticationEntryPoint()) .and() .addFilter(casAuthenticationFilter()) .addFilterBefore(casLogoutFilter(), LogoutFilter.class) .addFilterBefore(singleSignOutFilter(), CasAuthenticationFilter.class); //http.csrf().disable(); //禁用CSRF } /**认证的入口*/ @Bean public CasAuthenticationEntryPoint casAuthenticationEntryPoint() { CasAuthenticationEntryPoint casAuthenticationEntryPoint = new CasAuthenticationEntryPoint(); casAuthenticationEntryPoint.setLoginUrl(casProperties.getCasServerLoginUrl()); casAuthenticationEntryPoint.setServiceProperties(serviceProperties()); return casAuthenticationEntryPoint; } /**指定service相关信息*/ @Bean public ServiceProperties serviceProperties() { ServiceProperties serviceProperties = new ServiceProperties(); serviceProperties.setService(casProperties.getAppServerUrl() + casProperties.getAppLoginUrl()); serviceProperties.setAuthenticateAllArtifacts(true); return serviceProperties; } /**CAS认证过滤器*/ @Bean public CasAuthenticationFilter casAuthenticationFilter() throws Exception { CasAuthenticationFilter casAuthenticationFilter = new CasAuthenticationFilter(); casAuthenticationFilter.setAuthenticationManager(authenticationManager()); casAuthenticationFilter.setFilterProcessesUrl(casProperties.getAppLoginUrl()); return casAuthenticationFilter; } /**cas 认证 Provider*/ @Bean public CasAuthenticationProvider casAuthenticationProvider() { CasAuthenticationProvider casAuthenticationProvider = new CasAuthenticationProvider(); casAuthenticationProvider.setAuthenticationUserDetailsService(customUserDetailsService()); //casAuthenticationProvider.setUserDetailsService(customUserDetailsService()); //这里只是接口类型,实现的接口不一样,都可以的。 casAuthenticationProvider.setServiceProperties(serviceProperties()); casAuthenticationProvider.setTicketValidator(cas20ServiceTicketValidator()); casAuthenticationProvider.setKey("casAuthenticationProviderKey"); return casAuthenticationProvider; } /*@Bean public UserDetailsService customUserDetailsService(){ return new CustomUserDetailsService(); }*/ /**用户自定义的AuthenticationUserDetailsService*/ @Bean public AuthenticationUserDetailsService<CasAssertionAuthenticationToken> customUserDetailsService(){ return new CustomUserDetailsService(); } @Bean public Cas20ServiceTicketValidator cas20ServiceTicketValidator() { return new Cas20ServiceTicketValidator(casProperties.getCasServerUrl()); } /**单点登出过滤器*/ @Bean public SingleSignOutFilter singleSignOutFilter() { SingleSignOutFilter singleSignOutFilter = new SingleSignOutFilter(); singleSignOutFilter.setCasServerUrlPrefix(casProperties.getCasServerUrl()); singleSignOutFilter.setIgnoreInitConfiguration(true); return singleSignOutFilter; } /**请求单点退出过滤器*/ @Bean public LogoutFilter casLogoutFilter() { LogoutFilter logoutFilter = new LogoutFilter(casProperties.getCasServerLogoutUrl(), new SecurityContextLogoutHandler()); logoutFilter.setFilterProcessesUrl(casProperties.getAppLogoutUrl()); return logoutFilter; } }
6 .사용자 정의 클래스
(1) 편리한 사용을 위해 속성 파일에 지정된 내용을 삽입하는 CasProperties를 정의합니다. 여기에 인젝션하지 않는 것도 가능하며, 현재 Spring 환경을 얻을 수 있습니다.
package com.chengli.springboot.properties; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; /** * CAS的配置参数 * @author ChengLi */ @Component public class CasProperties { @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; ......省略 getters setters 方法 }
(2) CustomUserDetailsService 클래스를 정의합니다.
package com.chengli.springboot.custom; import java.util.HashSet; import java.util.Set; import org.springframework.security.cas.authentication.CasAssertionAuthenticationToken; import org.springframework.security.core.userdetails.AuthenticationUserDetailsService; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UsernameNotFoundException; /** * 用于加载用户信息 实现UserDetailsService接口,或者实现AuthenticationUserDetailsService接口 * @author ChengLi * */ public class CustomUserDetailsService /* //实现UserDetailsService接口,实现loadUserByUsername方法 implements UserDetailsService { @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { System.out.println("当前的用户名是:"+username); //这里我为了方便,就直接返回一个用户信息,实际当中这里修改为查询数据库或者调用服务什么的来获取用户信息 UserInfo userInfo = new UserInfo(); userInfo.setUsername("admin"); userInfo.setName("admin"); Set<AuthorityInfo> authorities = new HashSet<AuthorityInfo>(); AuthorityInfo authorityInfo = new AuthorityInfo("TEST"); authorities.add(authorityInfo); userInfo.setAuthorities(authorities); return userInfo; }*/ //实现AuthenticationUserDetailsService,实现loadUserDetails方法 implements AuthenticationUserDetailsService<CasAssertionAuthenticationToken> { @Override public UserDetails loadUserDetails(CasAssertionAuthenticationToken token) throws UsernameNotFoundException { System.out.println("当前的用户名是:"+token.getName()); /*这里我为了方便,就直接返回一个用户信息,实际当中这里修改为查询数据库或者调用服务什么的来获取用户信息*/ UserInfo userInfo = new UserInfo(); userInfo.setUsername("admin"); userInfo.setName("admin"); Set<AuthorityInfo> authorities = new HashSet<AuthorityInfo>(); AuthorityInfo authorityInfo = new AuthorityInfo("TEST"); authorities.add(authorityInfo); userInfo.setAuthorities(authorities); return userInfo; } }
(3) 현재 로그인한 사용자의 권한 정보를 로드하고 GrantedAuthority 인터페이스를 구현하는 데 사용되는 AuthorityInfo 클래스를 정의합니다. 코드는 다음과 같습니다.
package com.chengli.springboot.custom; import org.springframework.security.core.GrantedAuthority; /** * 权限信息 * * @author ChengLi * */ public class AuthorityInfo implements GrantedAuthority { private static final long serialVersionUID = -175781100474818800L; /** * 权限CODE */ private String authority; public AuthorityInfo(String authority) { this.authority = authority; } @Override public String getAuthority() { return authority; } public void setAuthority(String authority) { this.authority = authority; } }
(4) UserInfo를 정의합니다. 현재 사용자 정보를 로드하고 UserDetails 인터페이스를 구현하는 데 사용되는 클래스입니다. 코드는 다음과 같습니다.
package com.chengli.springboot.custom; import java.util.Collection; import java.util.HashSet; import java.util.Set; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.userdetails.UserDetails; /** * 用户信息 * @、这里我写了几个较为常用的字段,id,name,username,password,可以根据实际的情况自己增加 * @author ChengLi * */ public class UserInfo implements UserDetails { private static final long serialVersionUID = -1041327031937199938L; /** * 用户ID */ private Long id; /** * 用户名称 */ private String name; /** * 登录名称 */ private String username; /** * 登录密码 */ private String password; private boolean isAccountNonExpired = true; private boolean isAccountNonLocked = true; private boolean isCredentialsNonExpired = true; private boolean isEnabled = true; private Set<AuthorityInfo> authorities = new HashSet<AuthorityInfo>(); ....省略getters setters 方法 }
CAS 서버를 실행하고 위의 주소를 애플리케이션에 추가합니다. 속성 파일을 실제 주소로 복사하여 실행합니다.
[관련 추천]
spring Aop을 사용한 비즈니스 구현에 대한 자세한 설명 레이어 mysql 읽기 및 쓰기 분리
3. Spring Boot는 MySQL 데이터베이스와 JPA 인스턴스의 샘플 코드 공유를 추가합니다
4. Restful 프로그램 개발을 위한 Spring Boot 튜토리얼
위 내용은 CAS 예제를 통합하기 위해 Spring Boot의 Spring 보안 사용 공유의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!