依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.11</version>
</dependency>
<dependency>
<groupId>net.unicon.cas</groupId>
<artifactId>cas-client-autoconfig-support</artifactId>
<version>2.3.0-GA</version>
</dependency>
配置
server:
port: 8088
#cas服务端的地址
cas:
server-url-prefix: http://test.sso.shanhaiyh.com
#cas服务端的登录地址
server-login-url: http://test.sso.shanhaiyh.com/login
#客户端访问地址
client-host-url: http://192.168.1.216:8088
#验证的协议
validation-type: cas
配置类 CasAutoConfig
package com.example.cas.config;
import net.unicon.cas.client.configuration.CasClientConfigurerAdapter;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Map;
@Configuration
public class CasAutoConfig extends CasClientConfigurerAdapter {
@Value("${cas.server-login-url}")
private String serverLoginUrl;
@Value("${cas.client-host-url}")
private String serverLocalUrl;
@Value("${cas.server-url-prefix}")
private String serverUrlPrefix;
@Override
public void configureAuthenticationFilter(FilterRegistrationBean authenticationFilter) {
Map<String, String> initParameters = authenticationFilter.getInitParameters();
initParameters.put("authenticationRedirectStrategyClass", "com.example.cas.config.CustomAuthRedirectStrategy");
}
@Override
public void configureValidationFilter(FilterRegistrationBean validationFilter) {
Map<String, String> initParameters = validationFilter.getInitParameters();
initParameters.put("encodeServiceUrl", "false");
// 配置地址,这里还可以配置很多,例如cas重定向策略等。
initParameters.put("ignorePattern", "/casLogin/*");
validationFilter.setInitParameters(initParameters);
super.configureAuthenticationFilter(validationFilter);
}
@Bean
public FilterRegistrationBean corsFilter() {
// 1.创建 CORS 配置对象
CorsConfiguration config = new CorsConfiguration();
// 支持域
ArrayList<String> strings = new ArrayList<>();
strings.add("http://192.168.1.216:8088");
config.setAllowedOriginPatterns(Collections.singletonList("*"));
// 是否发送 Cookie
config.setAllowCredentials(true);
// 支持请求方式
config.addAllowedMethod("*");
// 允许的原始请求头部信息
config.addAllowedHeader("*");
// 暴露的头部信息
config.addExposedHeader("*");
// 2.添加地址映射
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", config);
FilterRegistrationBean<CorsFilter> registrationBean = new FilterRegistrationBean<>();
registrationBean.setFilter(new CorsFilter(source));
registrationBean.setOrder(-2147483648);
return registrationBean;
}
}
解决前后端分离时跨越问题
package com.example.cas.config;
import com.example.cas.common.ResData;
import org.jasig.cas.client.authentication.AuthenticationRedirectStrategy;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
@Component
public class CustomAuthRedirectStrategy implements AuthenticationRedirectStrategy {
@Override
public void redirect(HttpServletRequest request, HttpServletResponse response, String s) throws IOException {
response.setCharacterEncoding("utf-8");
response.setContentType("application/json; charset=utf-8");
String url = request.getParameter("url");
if (!StringUtils.isEmpty(url)) {
url = "http://192.168.1.216:9528/";
}
PrintWriter out = response.getWriter();
String data = ResData.error(401, "登录认证失败,请重新登录", "http://test.sso.shanhaiyh.com/login?service=http://192.168.1.216:8088/casLogin?url=" + url).toString();
out.write(data);
out.flush();
out.close();
}
}
测试控制器
package com.example.cas.controller;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.example.cas.common.ResData;
import com.example.cas.vo.PowerRmiVo;
import org.jasig.cas.client.authentication.AttributePrincipal;
import org.jasig.cas.client.validation.AssertionImpl;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.List;
@Controller
public class CASController {
@Value("${cas.server-login-url}")
private String serverLoginUrl;
@Value("${cas.client-host-url}")
private String serverLocalUrl;
@GetMapping("/casLogin")
public String casLogin(HttpServletRequest request, HttpServletResponse response) throws IOException {
String url = request.getParameter("url");
if (!StringUtils.isEmpty(url)) {
url = "http://192.168.1.216:9528/";
}
//由于用户信息存储在session中,因此可以从session中获取到存储用户信息的AssertionImpl对象从而获取用户信息
HttpSession session = request.getSession();
AssertionImpl assertion = (AssertionImpl) session.getAttribute("_const_cas_assertion_");
String username = null;
String ssoUrl = "";
if (assertion != null) {
AttributePrincipal principal = assertion.getPrincipal();
username = principal.getName();
if (StringUtils.isEmpty(username)) {
ssoUrl = serverLoginUrl + "?service=" + URLEncoder.encode(serverLocalUrl + "/casLogin?url=" + url, StandardCharsets.UTF_8);
return "redirect:" + ssoUrl;
}
}
return "redirect:" + url;
}
@RequestMapping("/order")
@ResponseBody
public Object order(HttpServletRequest request) throws IOException {
return ResData.success(HttpServletResponse.SC_OK, "操作成功", request.getParameter("id"));
}
@RequestMapping("/casLogout")
@ResponseBody
public ResData casLogout(HttpSession session) throws IOException {
session.invalidate();
String ssoUrl = serverLoginUrl + "?service=" + URLEncoder.encode(serverLocalUrl + "/cas/casLogin", StandardCharsets.UTF_8);
return ResData.success(HttpServletResponse.SC_OK, "退出成功", ssoUrl);
}
@GetMapping("/getUserInfo")
@ResponseBody
public Object getUserInfo(HttpServletRequest request) throws IOException {
//由于用户信息存储在session中,因此可以从session中获取到存储用户信息的AssertionImpl对象从而获取用户信息
HttpSession session = request.getSession();
AssertionImpl assertion = (AssertionImpl) session.getAttribute("_const_cas_assertion_");
if (assertion != null) {
AttributePrincipal principal = assertion.getPrincipal();
String username = principal.getName();
return ResData.success(1, "操作成功", username);
}
return ResData.error(0, "操作失败", "");
}
@GetMapping("/getMenuList")
@ResponseBody
public Object getMenus(HttpServletRequest request) throws IOException {
//由于用户信息存储在session中,因此可以从session中获取到存储用户信息的AssertionImpl对象从而获取用户信息
HttpSession session = request.getSession();
AssertionImpl assertion = (AssertionImpl) session.getAttribute("_const_cas_assertion_");
if (assertion != null) {
AttributePrincipal principal = assertion.getPrincipal();
String username = principal.getName();
String url = "https://api.shanhaiyh.com/shiant-api-c/service";
List<PowerRmiVo> lists = null;
for (int i = 0; i < 3; i++) {
HttpResponse response = HttpRequest.get(url + "/shop/getMenuByUserName?userName=" + username).execute();
if (response != null) {
String body = response.body();
JSONObject jsonObject = JSON.parseObject(body);
Object code = jsonObject.get("code").toString();
if ("0".equals(code)) {
Object data1 = jsonObject.get("data");
lists = JSON.parseArray(data1.toString(), PowerRmiVo.class);
break;
}
}
}
return ResData.success(1, "操作成功", lists);
}
return ResData.error(0, "操作失败", "");
}
}
测试效果:
单点登录成功后通过用户查询到的菜单信息