springboot整合security+cas单点登陆
来源:互联网 发布:万能五笔 for mac os 编辑:程序博客网 时间:2024/05/19 22:52
参考:http://blog.csdn.net/cl_andywin/article/details/53998986
创建application.properties文件,加入以下内容:
#CAS服务地址cas.server.host.url=http://cas.XXXX.net/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=/admin/index.html#应用登出地址app.logout.url=/logout#应用服务名称app.server.name=http://localhost:8080
security配置文件SecurityConfig,项目启动的时候会执行,初始化security和cas的设置
/** * @author mu.shuntao * @create 2017-04-10 10:44 */@Configuration@EnableWebSecurity //禁用Boot的默认Security配置,配合@Configuration启用自定义配置(需要扩展WebSecurityConfigurerAdapter)@EnableGlobalMethodSecurity(prePostEnabled = true) //启用Security注解,例如最常用的@PreAuthorizepublic class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private CasProperties casProperties; /** * configure(AuthenticationManagerBuilder): 身份验证配置,用于注入自定义身份验证Bean和密码校验规则 * @param auth * @throws Exception */ @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { super.configure(auth); auth.authenticationProvider(casAuthenticationProvider()); } /** * configure(WebSecurity): Web层面的配置,一般用来配置无需安全检查的路径 * @param web * @throws Exception */ @Override public void configure(WebSecurity web) throws Exception { web.ignoring().antMatchers("/static/**", "/templates/**"); } /** * configure(HttpSecurity): Request层面的配置,对应XML Configuration中的<http>元素 * @param http * @throws Exception */ @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests()//配置安全策略 .antMatchers("/").permitAll()//所有请求都不需要验证 //.antMatchers("/admin/**").authenticated()//admin下请求需要验证 .and() .logout() .permitAll()//定义logout不需要验证 .and() .formLogin(); http.exceptionHandling().authenticationEntryPoint(casAuthenticationEntryPoint()) .and() .addFilter(casAuthenticationFilter()) .addFilterBefore(casLogoutFilter(), LogoutFilter.class) .addFilterBefore(singleSignOutFilter(), CasAuthenticationFilter.class); http.csrf().disable(); // 关闭spring security默认的frame访问限制 http.headers().frameOptions().sameOrigin(); } @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; }}
这里在指定service里设置的是,就是http://localhost:8080/admin/index.html路径,保证这个路径能正常返回,登陆成功后才能正常返回ticket,执行后面的CustomUserDetailsService类中的loadUserDetails方法 serviceProperties.setService(casProperties.getAppServerUrl() + casProperties.getAppLoginUrl());
User类,用于封装登陆成功后的用户信息,登陆成功后程序里获取用户信息可以使用
User userDetails = (User) SecurityContextHolder.getContext() .getAuthentication() .getPrincipal(); String username = userDetails.getUsername(); String id = userDetails.getId();
页面获取用户信息可以使用,如下为获取用户名
${Session.SPRING_SECURITY_CONTEXT.authentication.principal.username}
/** * @author mu.shuntao * @create 2017-04-10 13:59 */public class User implements UserDetails{ /** * 用户ID */ private String id; /** * 用户名称 */ private String name; /** * 登录名称 */ private String username; /** * 登录密码 */ private String password; private boolean isAccountNonExpired = true; //是否过期 private boolean isAccountNonLocked = true; //账户未锁定为true private boolean isCredentialsNonExpired = true; //证书不过期为true private boolean isEnabled = true; //是否可用 private Set<GrantedAuthority> authorities = new HashSet<GrantedAuthority>(); @Override public Collection<? extends GrantedAuthority> getAuthorities() { return authorities; } @Override public String getPassword() { return password; } @Override public String getUsername() { return username; } @Override public boolean isAccountNonExpired() { return isAccountNonExpired; } @Override public boolean isAccountNonLocked() { return isAccountNonLocked; } @Override public boolean isCredentialsNonExpired() { return isCredentialsNonExpired; } @Override public boolean isEnabled() { return isEnabled; } public String getId() { return id; } public void setId(String id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public void setUsername(String username) { this.username = username; } public void setPassword(String password) { this.password = password; } public void setAccountNonExpired(boolean accountNonExpired) { isAccountNonExpired = accountNonExpired; } public void setAccountNonLocked(boolean accountNonLocked) { isAccountNonLocked = accountNonLocked; } public void setCredentialsNonExpired(boolean credentialsNonExpired) { isCredentialsNonExpired = credentialsNonExpired; } public void setEnabled(boolean enabled) { isEnabled = enabled; }}
CustomUserDetailsService 类,cas服务登陆成功后会自动执行loadUserDetails方法,我的cas服务返回了所有用户信息,直接从json里取出用户信息封装到User里。如果cas服务只返回用户id,可以拿着id去数据库查用户信息。
/** * @author mu.shuntao * @create 2017-04-10 13:54 */public class CustomUserDetailsService implements AuthenticationUserDetailsService<CasAssertionAuthenticationToken> { @Override public UserDetails loadUserDetails(CasAssertionAuthenticationToken token) throws UsernameNotFoundException { User user = new User(); Map<String, Object> userAttributess = token.getAssertion().getPrincipal().getAttributes(); if (userAttributess != null) { String userInfoJson = String.valueOf(userAttributess.get("userInfo")); if (StringUtils.isNotEmpty(userInfoJson)) { JSONObject userInfo = JSONObject.parseObject(userInfoJson); String userAppJson = String.valueOf(userAttributess.get("userApp")); JSONArray jsonArray = JSONObject.parseArray(userAppJson); if (jsonArray != null && jsonArray.size() > 0) { boolean canLogin = false; for (int i = 0; i < jsonArray.size(); i++) { JSONObject appInfo = jsonArray.getJSONObject(i); //判断用户是否有该应用登陆权限 if (appInfo.get("appId").equals("abc")) { canLogin = true; break; } } // 如果可以登录系统则返回用户数据 if (canLogin) { user.setUsername(userInfo.getString("userName")); user.setName(userInfo.getString("userRealName")); user.setPassword(userInfo.getString("password")); user.setId(userInfo.getString("userId")); } } } } return user; }}
最后附上cas服务端给客服端返回自定义数据的方法,自定义一个类UserInfoPrincipalResolver ,实现PrincipalResolver 接口,主要是复写resolve方法
,在resolve方法里封装数据
public class UserInfoPrincipalResolver implements PrincipalResolver { private UserService userService; public void setUserService(UserService userService) { this.userService = userService; } /** * Factory to create the principal type. **/ @NotNull protected PrincipalFactory principalFactory = new DefaultPrincipalFactory(); private PasswordEncoder passwordEncoder = new PlainTextPasswordEncoder(); /** * Optional principal attribute name. */ protected String principalAttributeName; @Override public boolean supports(final Credential credential) { return true; } @Override public Principal resolve(final Credential credential) { UsernamePasswordCredential captchaCredential = (UsernamePasswordCredential) credential; final String principalId = extractPrincipalId(credential); if (principalId == null) { return null; } final Pair<String, Map<String, Object>> pair = convertPersonAttributesToPrincipal(principalId, captchaCredential); return this.principalFactory.createPrincipal(pair.getFirst(), pair.getSecond()); } /** * 设置传递给客户端的数据 * * @param extractedPrincipalId * @return */ protected Pair<String, Map<String, Object>> convertPersonAttributesToPrincipal(final String extractedPrincipalId, UsernamePasswordCredential credential) { final Map<String, Object> convertedAttributes = new HashMap<>(); String principalId = extractedPrincipalId; String username = credential.getUsername(); String encryptedPassword = this.getPasswordEncoder().encode(credential.getPassword()); if ("MD5".equals(credential.getPasswordFlag())) { encryptedPassword = credential.getPassword(); } UserEntity userEntityParam = new UserEntity(); userEntityParam.setUserName(username); userEntityParam.setPassword(encryptedPassword); UserEntity userEntity = this.userService.checkUserLogin(userEntityParam); userEntity = this.userService.getUserInfo(userEntity.getUserId()); UserAppEntity userAppEntity = new UserAppEntity(); userAppEntity.setUserId(userEntity.getUserId()); List<UserAppEntity> userAppEntityList = this.userService.findUserAppList(userAppEntity); convertedAttributes.put("userInfo", JSONObject.toJSONString(userEntity)); convertedAttributes.put("userApp", JSONObject.toJSONString(userAppEntityList)); return new Pair<>(principalId, convertedAttributes); } public void setPrincipalFactory(final PrincipalFactory principalFactory) { this.principalFactory = principalFactory; } /** * Sets the PasswordEncoder to be used with this class. * * @param passwordEncoder the PasswordEncoder to use when encoding * passwords. */ public void setPasswordEncoder(final PasswordEncoder passwordEncoder) { this.passwordEncoder = passwordEncoder; } /** * Method to return the PasswordEncoder to be used to encode passwords. * * @return the PasswordEncoder associated with this class. */ private PasswordEncoder getPasswordEncoder() { return this.passwordEncoder; } protected String extractPrincipalId(final Credential credential) { return credential.getId(); }}
- springboot整合security+cas单点登陆
- SpringBoot整合cas单点登录
- cas单点登录整合spring security
- springboot+springSecurity+springSessionDataRedis+CAS搭建集群单点登陆系统
- spring boot-整合CAS Client实现单点登陆验证
- CAS单点登陆
- Cas单点登陆配置
- CAS单点登陆原理
- CAS 单点登陆
- CAS单点登陆实践
- cas 单点登陆
- shiro cas 单点登陆
- cas 4.0 单点登陆
- CAS 单点登陆配置
- CAS 单点登陆
- CAS 单点登陆
- CAS 单点登陆
- CAS 单点登陆
- Oracle 11G RAC教程之集群安装(七)
- C# MemoryStream类
- linux utf-8及gbk编码环境安装配置强大的vim
- elasticsearch5 在windows下head插件的安装
- Hibernate注解方法使用总结
- springboot整合security+cas单点登陆
- 欢迎使用CSDN-markdown编辑器
- C语言模拟实现多态
- rJava安装及Java 开发R
- HierarchicalBeanFactory
- Oracle 11G RAC数据库安装(八)
- RSA公钥加密+(Euclid)欧几里德扩展算法
- rehHat6 网络配置相关文件
- 2017.05.12-2Springboot对数据库简单的增删(-)查