当前位置: 首页 > news >正文

办个人网站租空间wordpress邮件发送不出去

办个人网站租空间,wordpress邮件发送不出去,wordpress播放视频播放,北京城乡与建设厅官方网站查询一、项目背景 公司需要搭建单点登录服务, 使所有系统共用一套登录逻辑. 对比了多个方案之后, 选用了CAS. 因此首先要搭建CAS服务, 因为涉及到JDK、gradle等组件的版本,最终选择了6.3版本。 后端:SpringBoot 2.3.12(已集成SpringSecurity&a…

一、项目背景

公司需要搭建单点登录服务, 使所有系统共用一套登录逻辑.

对比了多个方案之后, 选用了CAS. 因此首先要搭建CAS服务, 因为涉及到JDK、gradle等组件的版本,最终选择了6.3版本。

后端:SpringBoot 2.3.12(已集成SpringSecurity,并接入SpringCloud Alibaba微服务)
前端:vue2

二、CAS简介

CAS是一个单点登录的开源框架,遵循apache2.0协议,代码托管在github上。

单点登录使用户仅需一次登录便可操作所有系统(系统可以是不同源,即不同的域名、IP及端口)。

CAS登录在前后端不分离的情况下,官方已经给了源码示例

但是在前后端分离的情况下,改动的代码会多一些。

之前翻过很多"大佬"的帖子,多少都有坑,有些人甚至直接给出了CAS不适合前后端分离的结论?!简直震惊四座。

三、实现思路

首先是Spring Security的登录流程:

  1. 用户在浏览器发起请求web系统私有资源 /private;
  2. SecurityFilterChain过滤器链路到达FilterSecurityInterceptor,
  3. 并抛出访问被拒绝的异常AccessDeniedException,
  4. ExceptionTranslationFilter捕获该异常并通过sendStartAuthentication方法进入CasAuthenticationEntryPoint(AuthenticationEntryPoint的实现类)
  5. CasAuthenticationEntryPoint设置重定向到CAS Server地址https://cas.poop.com/cas/login?service=https%3A%2F%2Fportal.popo.com%2Fwebapp%2Flogin/cas。
    Spring Security登录认证流程.jpg

然后是CAS认证的流程:

  1. 用户在CAS Server登录验证完后,携带ST跳转到客户端https://cas.poop.com/cas/login?service=https%3A%2F%2Fportal.popo.com%2Fwebapp%2Flogin/cas%3Fticket%3DST-0-ER94xMJmn6pha35CQRoZ) ,进入CasAuthenticationFilter;

  2. CasAuthenticationFilter将ST包装成UsernamePasswordAuthenticationToken请求AuthenticationManager进行认证处理;

  3. AuthenticationManager将认证委托给CasAuthenticationProvider;

  4. CasAuthenticationProvider使用TicketValidator向CAS Server发起ST校验请求https://cas.poop.com/cas/login?service=https%3A%2F%2Fportal.popo.com%2Fwebapp%2Flogin/cas&ticket=ST-0-ER94xMJmn6pha35CQRoZ,成功后获取用户登录信息。

  5. 最后,CasAuthenticationProvider使用AuthenticationUserDetailsService进行后置处理,一般获取更加详细的用户信息,例如权限等。

最后是CAS单点登录的总体流程, 流程并不复杂,引用大佬的一张图:

cas登录流程.png

前后端分离的CAS验证流程, 涉及到三个模块,分别为系统前端、系统后端及单点登录CAS服务,流程可以简单概括为三步:

  • 第一步:前端访问后端,后端发现未登陆,重定向至CAS服务进行登录。
  • 第二步:登录成功后,CAS服务携带登录成功的ticket凭证跳转回前端, 写入jsessionid。
  • 第三步:前端拿到ticket访问后端进行验证,若验证成功则为登录成功, 返回token。

四、后端代码实现

1. 引入依赖
<!--    spring security    -->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency><groupId>org.springframework.security</groupId><artifactId>spring-security-cas</artifactId>
</dependency>
2. 修改配置文件

application.yml:

cas:server: http://localhost:8080/casclient: http://localhost:9527

配置文件增加两个URL,其中cas.server为CAS端的调用地址,cas.client为本系统前端的地址。

3. 修改SpringSecurity代码

SecurityConfig.java - 基于CAS调整SpringSecurity的配置

import com.alibaba.fastjson.JSON;
import com.example.service.impl.admin.structure.CasPersonServiceImpl;
import com.example.util.Response;
import org.jasig.cas.client.session.SingleSignOutFilter;
import org.jasig.cas.client.validation.Cas20ServiceTicketValidator;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.http.HttpMethod;
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.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 javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {// 配置文件中的CAS服务器地址@Value("${cas.server}")private String casServerUrl;// 配置文件中的本应用前端地址@Value("${cas.client}")private String casClientUrl;private static final String[] PERMIT_URL = new String[]{"/login/cas", "/logout/cas", "/loginUser", "/bye", "/v2/**", "/permission"};// 自定义的用户信息类(用于ticket验证成功后获取用户信息的逻辑)private final CasPersonServiceImpl casPersonService;/*** 构造函数*/public SecurityConfig(CasPersonServiceImpl casPersonService) {this.casPersonService = casPersonService;}/*** SpringSecurity配置*/@Overrideprotected void configure(HttpSecurity http) throws Exception {http// 配置接口过滤网,放行/login/cas用于单点登录的验证.authorizeRequests().antMatchers(PERMIT_URL).permitAll().anyRequest().authenticated().and().httpBasic()// 配置自定义的用户认证入口类(用于处理未登录或登录超时的逻辑).authenticationEntryPoint(casAuthenticationEntryPoint()).and()// 配置自定义的CAS用户认证入口类.addFilter(casAuthenticationFilter())// 配置CAS需要用到的其他类.addFilterBefore(singleSignOutFilter(), CasAuthenticationFilter.class).addFilterBefore(casLogoutFilter(), LogoutFilter.class)// 禁用CORS// 禁用CSRF.csrf().disable();}/*** CAS配置(AuthenticationProvider)*/@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {super.configure(auth);auth.authenticationProvider(casAuthenticationProvider());}/*** CAS:认证入口*/@Beanpublic CasAuthenticationEntryPoint casAuthenticationEntryPoint() {CasAuthenticationEntryPoint casAuthenticationEntryPoint = new CasAuthenticationEntryPoint();casAuthenticationEntryPoint.setLoginUrl(casServerUrl + "/login");casAuthenticationEntryPoint.setServiceProperties(serviceProperties());return casAuthenticationEntryPoint;}/*** CAS:服务配置*/@Beanpublic ServiceProperties serviceProperties() {ServiceProperties serviceProperties = new ServiceProperties();// 此处填入前端登录页面的地址serviceProperties.setService(casClientUrl + "/#/login/cas");serviceProperties.setAuthenticateAllArtifacts(true);return serviceProperties;}/*** CAS:配置自定义的CAS用户认证入口类*/@Beanpublic CasAuthenticationFilter casAuthenticationFilter() throws Exception {CasAuthenticationFilter casAuthenticationFilter = new CasAuthenticationFilter();casAuthenticationFilter.setAuthenticationManager(authenticationManager());casAuthenticationFilter.setFilterProcessesUrl("/login/cas");casAuthenticationFilter.setServiceProperties(serviceProperties());// 重要:此处为配置ticket验证成功后的逻辑,默认为重定向到首页,因前后端分离,仅需要返回成功即可。casAuthenticationFilter.setAuthenticationSuccessHandler((request, response, authentication) -> {response.setStatus(HttpServletResponse.SC_OK);PrintWriter out = response.getWriter();out.write("{\"status\":" + "\"200\"" + "}");});casAuthenticationFilter.setAuthenticationFailureHandler((request, response, e) -> {response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);PrintWriter out = response.getWriter();out.write("{\"code\":401" + ",\"message\":\"Ticket verified failed!\"}");logger.error("单点登录验证失败", e);});return casAuthenticationFilter;}/*** CAS:CAS的核心,CasAuthenticationProvider*/@Beanpublic CasAuthenticationProvider casAuthenticationProvider() {CasAuthenticationProvider casAuthenticationProvider = new CasAuthenticationProvider();casAuthenticationProvider.setAuthenticationUserDetailsService(customUserDetailsService());casAuthenticationProvider.setServiceProperties(serviceProperties());casAuthenticationProvider.setTicketValidator(cas20ServiceTicketValidator());casAuthenticationProvider.setKey("EXAMPLE_CAS_PROVIDER");return casAuthenticationProvider;}/*** CAS:自定义的用户认证入口类(用于处理未登录或登录超时的逻辑)*/@Beanpublic AuthenticationUserDetailsService<CasAssertionAuthenticationToken> customUserDetailsService() {return casPersonService;}/*** CAS:ticket验证类*/@Beanpublic Cas20ServiceTicketValidator cas20ServiceTicketValidator() {return new Cas20ServiceTicketValidator(casServerUrl);}/*** CAS:SingleSignOutFilter*/@Beanpublic SingleSignOutFilter singleSignOutFilter() {SingleSignOutFilter singleSignOutFilter = new SingleSignOutFilter();singleSignOutFilter.setIgnoreInitConfiguration(true);return singleSignOutFilter;}/*** CAS:LogoutFilter*/@Beanpublic LogoutFilter casLogoutFilter() {LogoutFilter logoutFilter = new LogoutFilter(casServerUrl + "/logout?service=" + casClientUrl,new SecurityContextLogoutHandler());logoutFilter.setFilterProcessesUrl("/logout/cas");return logoutFilter;}}

CasPersonServiceImpl.java - 自定义的用户信息类(用于ticket验证成功后获取用户信息的逻辑)

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.example.config.SecurityToken;
import com.example.entity.admin.structure.Person;
import com.example.entity.admin.structure.PersonView;
import com.example.service.admin.structure.PersonService;
import com.example.service.admin.structure.PersonViewService;
import com.example.util.Strings;
import org.jasig.cas.client.validation.Assertion;
import org.springframework.security.authentication.AccountExpiredException;
import org.springframework.security.authentication.LockedException;
import org.springframework.security.cas.userdetails.AbstractCasAssertionUserDetailsService;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;import java.util.ArrayList;
import java.util.List;@Service
public class CasPersonServiceImpl extends AbstractCasAssertionUserDetailsService {private final PersonService personService;public CasPersonServiceImpl(PersonService personService) {this.personService = personService;}/*** 此处为ticket验证成功后,使用CAS返回的用户名在本地获取用户数据的逻辑,可自定义。* 需要返回一个UserDetails,此处自定义了token类SecurityToken,* 继承自org.springframework.security.core.userdetails.User即可。*/@Overrideprotected UserDetails loadUserDetails(Assertion assertion) {// 查找用户String username = assertion.getPrincipal().getName();Person person = personService.getOne(new QueryWrapper<Person>().lambda().eq(Person::getUsername, username));if (person == null) throw new UsernameNotFoundException("用户不存在");if (person.getIsLocked() == 1) throw new LockedException("账户已锁定");if (!"ACTIVE".equals(person.getStatus())) throw new AccountExpiredException("账户已失效");// 查询角色List<GrantedAuthority> authorities = new ArrayList<>();if (person.getIsAdmin() == 1) authorities.add(new SimpleGrantedAuthority(Strings.ROLE_ADMIN));// 用户信息SecurityToken token = new SecurityToken(person.getUsername(), person.getPassword(), authorities);token.setInfo(person);return token;}}

五、前端代码

前端部分需要处理的的逻辑大概为:

  1. 添加/login/cas页面, 当进入此页面时(CAS重定向回来), 获取地址中ticket参数, 注意要进行解码; 如果页面是路由的方式(例如/#/login/cas), 则url会是localhost:9527/myView?ticket=***/#/login/cas的格式, 需要将/#/login/cas去掉。

  2. 携带ticket参数访问后端的/login/cas, (后端Security注意放行该请求路径)验证ticket。

  3. 验证成功后会自动返回set-cookie的头,里边包含了jsessionId,后续正常访问接口时则会判断为已登录。

  4. 登录成功后跳转至index首页, 如果页面是路由的方式(例如/#/index), 则url会携带ticket参数, 形如localhost:9527/myView?ticket=***/#/index的格式, 需要将ticket去掉, 参考代码:

let newUrl = window.location.origin + '/' + window.location.hashwindow.history.pushState({}, '', newUrl);
this.$router.push({ path: this.redirect || '/' })
http://www.dtcms.com/a/402831.html

相关文章:

  • 云南网站建设网站运营wordpress 总站模板
  • 带注册的网站需要多大空间信阳建设网站
  • 用jsp做电影网站的界面建设网站需要哪些
  • 中国建设银行投诉网站有关建设网站的英语文献
  • 南通网站群建设广州网站推广软件
  • 滨州网站建设公司刷网站建设
  • 网站建设与营销服务wordpress 下载类主题
  • 南京网站官网建设网络公司网站创建
  • 泰和县城乡建设局网站免费网站的app
  • 正规的邯郸网站建设网站推广分析
  • 好的免费网站建站平台wordpress 精简主题
  • 微信网站开发制作公司青云 wordpress
  • 做个人网站用什么程序网站设计技术
  • 如何做网站的悬浮窗口网站建设前台后台
  • 重庆做网站 熊掌号苏州网站设计公司排名
  • 宁波网站推广优化公司电话宁国网站开发
  • 可信网站认证不在有用吗个人电子邮箱怎么填写格式
  • 怎么做招聘网站的调研wordpress首页生成静态页面
  • 网站建设评分标准公司做的网站怎么维护
  • 一个人做运营网站食品包装设计分析
  • 网站运营问题宜春做网站的联系电话
  • 石家庄外贸网站推广wordpress企业主题下载
  • 邢台做网站邮箱用户登录入口
  • 网站关键词布局图大同本地做网站的
  • 音乐播放网站开发pc端外贸累网站
  • sns网站开发没有备案号的网站
  • 网站建设网站备案所需资料网站建设昆明
  • 网站 攻击网站建设备案需要什么
  • 做盗链电影网站怎么样济南网站建设建站
  • 网站怎么做微信登录外包公司做网站