SpringBoot前后端分离整合cas(客户端)
cas认证详细流程:
前后端分离:项目前端使用nginx启动,后端是springBoot服务;
nginx可以统一管理Cookie,避免出现跨域问题。
添加依赖
<dependency>
<groupId>org.jasig.cas.client</groupId>
<artifactId>cas-client-support-springboot</artifactId>
<version>3.6.2</version>
</dependency>
配置文件添加
cas:
# cas服务端地址,nginx代理
server-url-prefix: http://127.0.0.1:9010/cas
# cas服务端登录地址,nginx代理
server-login-url: http://127.0.0.1:9010/cas/login
# 当前服务程序地址,nginx代理
client-host-url: http://127.0.0.1:9010
validation-type: cas3
# 不校验权限路径(正则表达式)
ignorePattern: ".*\\/api\\/rest\\/test\\/.*|.*\\/test\\/hello"
启动类添加注解@EnableCasClient
@EnableCasClient
@SpringBootApplication
public class TestApplication extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(TobApplication.class, args);
}
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(TobApplication.class);
}
}
重写cas客户端配置
@Configuration
public class SmsCasClientConfigurer implements CasClientConfigurer {
@Value("${host-url}")
private String serverName;
@Value("${ignorePattern}")
private String ignorePattern;
@Value("${cas.server-login-url}")
private String serverLoginUrl;
@Value("${casLogin-url}")
private String casLoginUrl;
@Override
public void configureAuthenticationFilter(FilterRegistrationBean authenticationFilter) {
Map initParameters = authenticationFilter.getInitParameters();
// 设置不校验权限路径
initParameters.put("ignorePattern", ignorePattern);
}
}
默认Get接口
@RestController
@RequestMapping("/api/common")
public class CommonController {
@GetMapping("/getUserName")
public String getUserName(HttpServletRequest request) {
if(request.getUserPrincipal()!=null){
return request.getUserPrincipal().getName();
}else{
return "";
}
}
前端添加拦截
我的前端使用的vue,若不是可以参考文章底部博客。
前端登陆之后cas服务端会默认添加"TGC"的cookie到浏览器,然后会跳转到前端页面,前端首次去访问后端程序时需要验证票据,所以默认第一个请求接口尽量是get请求,若是post可能会被cas重定向成get。下面的2,3步你也可以不做,直接在路由守卫permission.js中直接调用接口,根据自己的实际情况使用此博客即可。
1,get请求接口src\api\commonAPI.js
import { httpServer } from 'axios'
export function getUserNameAPI (data) {
return httpServer.get(`api/common/getUserName`);
}
2,设置缓存src\store\modules\user.js
import { getUserNameAPI } from "@/api/commonAPI.js";
const state = {
username: ""
}
/*从session获取username,vue页面中可调用:如下示例
...
{{getUserName}}
...
computed: {
...mapGetters(["getUserName"]),
}
...
*/
const getters = {
getUserName: state => {
var name;
if (sessionStorage.getItem('username')) {
name= sessionStorage.getItem('username');
} else {
name= state.username;
}
return name;
}
}
const mutations = {
["SET_USER_NAME"](state, data) {
state.username = data === null ? "" : data;
sessionStorage.setItem('username',data)
}
}
//调用接口并添加username到session中
const actions = {
getUserName({commit}) {
return new Promise(resolve => {
getUserNameAPI().then(res => {
commit("SET_USER_NAME", res);
resolve()
});
})
}
}
export default {
state,
getters,
mutations,
actions
};
3,添加user.js到src\store\index.js
import Vue from "vue";
import Vuex from "vuex";
import createPersistedState from "vuex-persistedstate";
import user from "./modules/user";
Vue.use(Vuex);
export default new Vuex.Store({
modules: {
user
},
plugins: [createPersistedState({ storage: window.sessionStorage })]
});
4,修改路由守卫src\permission.js
//路由拦截
import {Spin} from "view-design";
import "view-design/dist/styles/iview.css";
import router from "./router";
import store from "./store";
import Cookies from "js-cookie";
Spin.show({
render: (h) => {
return h('div', [
h('div', '登录中...')
])
}
})
router.beforeEach((to, from, next) => {
//走cas校验
if(true){
let CUR_URL = window.location.href;
//判断是否存在TGC的Cookies,不存在则跳转到cas登录页面登录,登陆成功之后cas服务端会添加TGC的Cookies到浏览器中
let CASTGC_COOKIE = Cookies.get("TGC")?true:false;
if (CASTGC_COOKIE) {
// 登录
if (CUR_URL.indexOf("?ticket") > -1) {
window.location.href = CUR_URL.split("?ticket")[0];
}
Promise.all([store.dispatch('getUserName')]).then(opts => {
Spin.hide();
next();
})
} else {
window.location.href = `http://127.0.0.1:9010/cas/login?service=${window.location}`;
}
} else {
//不走cas校验
Promise.all([store.dispatch('getUserName')]).then(opts => {
Spin.hide();
next();
})
}
});
nginx代理
worker_processes 1;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
server {
listen 9010;
server_name 127.0.0.1;
#nginx代理前端
location / {
autoindex on;
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
# 静态资源位置
alias /usr/share/nginx/html;
index index.html;
try_files $uri $uri/ /index.html last;
}
#我的后端服务,my_server为我的服务前缀
location ^~ /my_server/ {
proxy_pass http://127.0.0.1:8091/my_server/;
add_header Access-Control-Allow-Origin *;
proxy_cookie_path /my_server/ /; #解决nginx转发丢失cookie的问题
# 支持 OPTIONS 请求,并设置预检请求结果的缓存时间
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Max-Age' 1728000;
add_header 'Content-Type' 'text/plain charset=UTF-8';
add_header 'Content-Length' 0;
return 204;
}
}
#cas服务端
location ^~ /cas/ {
proxy_pass http://127.0.0.1:8092/cas/;
add_header Access-Control-Allow-Origin *;
proxy_cookie_path /cas/ /; #解决nginx转发丢失cookie的问题
# 支持 OPTIONS 请求,并设置预检请求结果的缓存时间
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Max-Age' 1728000;
add_header 'Content-Type' 'text/plain charset=UTF-8';
add_header 'Content-Length' 0;
return 204;
}
}
}
}
参考博客:
https://blog.csdn.net/weixin_41358538/article/details/130880319