Commit e4b4a2b6 by linxu

add cas support

parent c0ac0020
...@@ -79,6 +79,18 @@ ...@@ -79,6 +79,18 @@
<groupId>org.springframework.cloud</groupId> <groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-client</artifactId> <artifactId>spring-cloud-config-client</artifactId>
</dependency> </dependency>
<dependency>
<groupId>com.kakawait</groupId>
<artifactId>cas-security-spring-boot-starter</artifactId>
<version>1.0.0-beta-1</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
<version>1.4.5.RELEASE</version>
</dependency>
</dependencies> </dependencies>
<dependencyManagement> <dependencyManagement>
......
...@@ -7,6 +7,7 @@ public class Constants { ...@@ -7,6 +7,7 @@ public class Constants {
public static final String Session_UserDName = "userDName"; public static final String Session_UserDName = "userDName";
public static final String Session_Roles = "roles"; public static final String Session_Roles = "roles";
public static final String Session_Lang = "lang"; public static final String Session_Lang = "lang";
public static final String ROLE_PREFIX = "ROLE_";
} }
package com.keymobile.proxy.conf;
import feign.auth.BasicAuthRequestInterceptor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class FeignClientConfig {
@Value("${security.authUser}")
private String authUser;
@Value("${security.authPwd}")
private String authPwd;
@Bean
public BasicAuthRequestInterceptor getBasicAuthRequestInterceptor() {
return new BasicAuthRequestInterceptor(authUser, authPwd);
}
}
\ No newline at end of file
package com.keymobile.proxy.conf; package com.keymobile.proxy.conf;
import com.keymobile.proxy.model.CasProperties;
import com.keymobile.proxy.service.CustomUserDetailsService;
import org.jasig.cas.client.validation.Cas20ServiceTicketValidator;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; 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.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.password.NoOpPasswordEncoder; import org.springframework.security.core.userdetails.AuthenticationUserDetailsService;
import javax.sql.DataSource;
@Configuration @Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter { public class SecurityConfig extends WebSecurityConfigurerAdapter {
private static final String usersQuery = "select concat(user_name, ':', user_id, ':', user_dname), password, true \n" +
"from auth_user where user_name = ?";
private static final String rolesQuery = "select t1.user_name, concat(concat('ROLE_', t1.author_name), ':', GROUP_CONCAT(COALESCE(t2.domain_id, '*'))) as role_name \n" +
"from \n" +
" (select a.user_name, d.author_name\n" +
" from auth_user a, auth_user_roles b, auth_role_authors c, auth_author d\n" +
" where a.user_id = b.user_id and b.role_id = c.role_id and c.author_id = d.author_id\n" +
" and a.user_name = substring_index(?, ':', 1)) t1\n" +
" left join\n" +
" (select a.user_name, c.domain_id\n" +
" from auth_user a, auth_user_domains b, auth_domain c\n" +
" where a.user_id = b.user_id and b.domain_id = c.domain_id) t2\n" +
"on t1.user_name = t2.user_name \n" +
"group by t1.author_name";
@Autowired
private DataSource dataSource;
@Autowired
private RESTAuthenticationEntryPoint authenticationEntryPoint;
@Autowired
private RESTAuthenticationFailureHandler authenticationFailureHandler;
@Autowired @Autowired
private RESTAuthenticationSuccessHandler authenticationSuccessHandler; private CasProperties casProperties;
@Autowired
private RESTLogoutSuccessHandler logoutSuccessHandler;
@Autowired @Autowired
public void configure(AuthenticationManagerBuilder auth) throws Exception { public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.jdbcAuthentication().usersByUsernameQuery(usersQuery).authoritiesByUsernameQuery(rolesQuery) super.configure(auth);
.dataSource(dataSource).passwordEncoder(NoOpPasswordEncoder.getInstance()); auth.authenticationProvider(casAuthenticationProvider());
} }
@Override @Override
protected void configure(HttpSecurity http) throws Exception { protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().anyRequest().permitAll(); http.authorizeRequests().antMatchers("/api/info/**/*").authenticated()
.antMatchers("/api/**/*").permitAll()
.anyRequest().authenticated();
http.exceptionHandling().authenticationEntryPoint(casAuthenticationEntryPoint()).and()
.addFilter(casAuthenticationFilter());
http.csrf().disable(); http.csrf().disable();
http.exceptionHandling().authenticationEntryPoint(authenticationEntryPoint); }
http.formLogin().successHandler(authenticationSuccessHandler);
http.formLogin().failureHandler(authenticationFailureHandler); /**认证的入口*/
http.formLogin().loginPage("/login"); @Bean
http.formLogin().loginProcessingUrl("/signin"); public CasAuthenticationEntryPoint casAuthenticationEntryPoint() {
http.logout().logoutUrl("/signout"); CasAuthenticationEntryPoint casAuthenticationEntryPoint = new CasAuthenticationEntryPoint();
http.logout().logoutSuccessHandler(logoutSuccessHandler); casAuthenticationEntryPoint.setLoginUrl(casProperties.getCasServerLoginUrl());
casAuthenticationEntryPoint.setServiceProperties(serviceProperties());
return casAuthenticationEntryPoint;
}
/**CAS认证过滤器*/
@Bean
public CasAuthenticationFilter casAuthenticationFilter() throws Exception {
CasAuthenticationFilter casAuthenticationFilter = new CasAuthenticationFilter();
casAuthenticationFilter.setAuthenticationManager(authenticationManager());
casAuthenticationFilter.setFilterProcessesUrl(casProperties.getAppLoginUrl());
return casAuthenticationFilter;
}
@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;
}
/**指定service相关信息*/
@Bean
public ServiceProperties serviceProperties() {
ServiceProperties serviceProperties = new ServiceProperties();
serviceProperties.setService(casProperties.getAppServerUrl() + casProperties.getAppLoginUrl());
serviceProperties.setAuthenticateAllArtifacts(true);
return serviceProperties;
}
@Bean
public Cas20ServiceTicketValidator cas20ServiceTicketValidator() {
return new Cas20ServiceTicketValidator(casProperties.getCasServerUrl());
}
/**用户自定义的AuthenticationUserDetailsService*/
@Bean
public AuthenticationUserDetailsService<CasAssertionAuthenticationToken> customUserDetailsService(){
return new CustomUserDetailsService();
} }
} }
package com.keymobile.proxy.model;
public class Author {
private Long id;
private String name;
public Author() {}
public Long getAuthorId() {
return id;
}
public void setAuthorId(Long id) {
this.id = id;
}
public String getAuthorName() {
return name;
}
public void setAuthorName(String name) {
this.name = name;
}
}
package com.keymobile.proxy.model;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
/**
* CAS的配置参数
*/
@Component
public class CasProperties {
@Value("${security.cas.server.base-url}")
private String casServerUrl;
@Value("${security.cas.server.paths.login}")
private String casServerLoginUrl;
@Value("${security.cas.service.base-url}")
private String appServerUrl;
@Value("${security.cas.service.paths.login}")
private String appLoginUrl;
public String getCasServerUrl() {
return casServerUrl;
}
public String getCasServerLoginUrl() {
return casServerLoginUrl;
}
public String getAppServerUrl() {
return appServerUrl;
}
public String getAppLoginUrl() {
return appLoginUrl;
}
}
package com.keymobile.proxy.model;
public class Domain {
private Long id;
private String name;
public Domain() {}
public Domain(String name) {
this.name = name;
}
public Long getDomainId() {
return id;
}
public void setDomainId(Long id) {
this.id = id;
}
public String getDomainName() {
return name;
}
public void setDomainName(String name) {
this.name = name;
}
}
package com.keymobile.proxy.model;
public class Role {
private Long id;
private String name;
private String dname;
public Role() {}
public Long getRoleId() {
return id;
}
public void setRoleId(Long id) {
this.id = id;
}
public String getRoleName() {
return name;
}
public void setRoleName(String name) {
this.name = name;
}
public String getRoleDName() {
return dname;
}
public void setRoleDName(String dname) {
this.dname = dname;
}
}
package com.keymobile.proxy.model;
import java.util.List;
public class User {
private Long id;
private String name;
private String dname;
private String password;
private List<Role> roles;
private List<Domain> domains;
public User() {}
public void setId(Long id) {
this.id = id;
}
public Long getId() {
return id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDName() {
return dname;
}
public void setDName(String dname) {
this.dname = dname;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
System.out.println(password);
this.password = password;
}
public List<Role> getRoles() {
return roles;
}
public void setRoles(List<Role> roles) {
this.roles = roles;
}
public List<Domain> getDomains() {
return domains;
}
public void setDomains(List<Domain> domains) {
this.domains = domains;
}
}
\ No newline at end of file
package com.keymobile.proxy.service;
import com.keymobile.proxy.model.Author;
import com.keymobile.proxy.model.Domain;
import com.keymobile.proxy.model.Role;
import com.keymobile.proxy.model.User;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@FeignClient(value = "authService")
public interface AuthService {
@RequestMapping(value = "/user")
User getUserByName(@RequestParam(value = "name") String name);
@PostMapping(value = "/users/{userId}")
User updateUser(@PathVariable(value = "userId") Long userId, @RequestBody User user);
@RequestMapping(value = "/users", method = RequestMethod.POST)
User addUser(@RequestParam(value = "roleIds", required = false) Long[] roleIds
, @RequestParam(value = "domainIds", required = false) Long[] domainIds, @RequestBody User user);
@RequestMapping(value = "/roles/{roleId}/authors", method = RequestMethod.GET)
List<Author> getAuthorsOfRole(@PathVariable(value = "roleId") Long roleId);
@RequestMapping(value = "/users/{userId}/roles", method = RequestMethod.GET)
List<Role> getRolesOfUser(@PathVariable(value = "userId") Long userId);
@RequestMapping(value = "/users/{userId}/domains", method = RequestMethod.GET)
List<Domain> getDomainsOfUser(@PathVariable(value = "userId") Long userId);
}
package com.keymobile.proxy.service;
import com.keymobile.proxy.api.Constants;
import com.keymobile.proxy.model.Author;
import com.keymobile.proxy.model.Domain;
import com.keymobile.proxy.model.Role;
import com.keymobile.proxy.util.HttpUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.cas.authentication.CasAssertionAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.AuthenticationUserDetailsService;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.util.StringUtils;
import javax.servlet.http.HttpSession;
import java.util.ArrayList;
import java.util.List;
/**
* 用于加载用户信息 实现UserDetailsService接口,或者实现AuthenticationUserDetailsService接口
*
*/
public class CustomUserDetailsService
//实现AuthenticationUserDetailsService,实现loadUserDetails方法
implements AuthenticationUserDetailsService<CasAssertionAuthenticationToken> {
@Autowired
private AuthService authService;
private Logger logger = LoggerFactory.getLogger(CustomUserDetailsService.class);
@Override
public UserDetails loadUserDetails(CasAssertionAuthenticationToken token) throws UsernameNotFoundException {
System.out.println("当前的用户名是:"+token.getName());
com.keymobile.proxy.model.User u = this.authService.getUserByName(token.getName());
if (u == null) {
u = new com.keymobile.proxy.model.User();
u.setName(token.getName());
u.setPassword("37fa265330ad83eaa879efb1e2db6380896cf639");
u.setDName(token.getName());
u = this.authService.addUser(new Long[] { (long) 4 }, new Long[] {}, u);
this.logger.info(u ==null ? "u is null":u.toString());
}
List<GrantedAuthority> authorities = new ArrayList<>();
String userDomainFilterStr = "*";
List<String> userDomainList = new ArrayList<>();
List<Domain> domainsOfUser = authService.getDomainsOfUser(u.getId());
domainsOfUser.forEach(d -> userDomainList.add(d.getDomainId().toString()));
if (userDomainList.size() > 0) {
userDomainFilterStr = String.join(",", userDomainList);
}
List<Role> rolesOfUser = authService.getRolesOfUser(u.getId());
for (Role role : rolesOfUser) {
List<Author> authors = authService.getAuthorsOfRole(role.getRoleId());
for (Author author: authors) {
GrantedAuthority authorityInfo = new SimpleGrantedAuthority(Constants.ROLE_PREFIX + author.getAuthorName() + ":" + userDomainFilterStr);
authorities.add(authorityInfo);
}
}
List<String> roles = new ArrayList<>();
authorities.forEach(auth -> roles.add(auth.getAuthority()));
HttpSession session = HttpUtil.getSession();
if (session != null) {
session.setAttribute(Constants.Session_UserId, u.getId());
session.setAttribute(Constants.Session_UserName, u.getName());
session.setAttribute(Constants.Session_UserDName, u.getDName());
session.setAttribute(Constants.Session_Roles, roles);
}
return new User(u.getName()+ ":" + u.getId() + ":" + u.getDName(),"37fa265330ad83eaa879efb1e2db6380896cf639" ,authorities);
}
}
package com.keymobile.proxy.util;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
public class HttpUtil {
public static HttpServletRequest getRequest() {
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
return attributes.getRequest();
}
public static HttpSession getSession () {
HttpSession session = null;
try {
session = getRequest().getSession();
} catch (Exception e) {
}
return session;
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment