CAS
1.下载安装Cas
由于6.0以上的版本需要JDK11,所以这里下载5.3(maven3.3/jdk8)
- 下载后导入到Idea中,右键-git-branchs 切换到5.3
- 命令行输入
mvn clean package
- 执行完毕之后在target目录下找到cas.war
- 用Tomcat运行这个war,浏览器访问
- application.properties中修改账号密码,默认:casuser/Mellon
- 由于CAS默认使用的是基于https协议,需要改为兼容使用http协议,并修改端口为8080
cas.authn.accept.users=root::123123
#兼容 Http 协议
cas.tgc.secure=false
# 开启识别Json文件,默认false
cas.serviceRegistry.initFromJson=true
# 允许退出登录后重定向到其他页面
cas.logout.followServiceRedirects=true
- 默认的Https添加http cas\WEB-INF\classes\services目录下的HTTPSandIMAPS-10000001.json 修改内容如下,即添加http
"serviceId" : "^(https|http|imaps)😕/.*",
2.客户端1:8088
- 依赖
<dependency>
<!--第三方starter,可免去配置类,不过它没有配置登出,可手动注册登出bean-->
<groupId>net.unicon.cas</groupId>
<artifactId>cas-client-autoconfig-support</artifactId>
<version>2.1.0-GA</version>
</dependency>
- 配置
server.port=8088
#cas服务端的地址
cas.server-url-prefix=http://localhost:8080/cas
#cas服务端的登录地址
cas.server-login-url=http://localhost:8080/cas/login
#当前服务器的地址(客户端)
cas.client-host-url=http://localhost:8088
#Ticket校验器使用Cas30ProxyReceivingTicketValidationFilter
cas.validation-type=cas3
import net.unicon.cas.client.configuration.EnableCasClient;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@EnableCasClient//开启cas客户端服务
@SpringBootApplication
public class CasApplication {
public static void main(String[] args) {
SpringApplication.run(CasApplication.class, args);
}
@Value(value = "${cas.client-host-url}")
private String server_name ;
@Value(value = "${cas.server-login-url}")
private String login_url ;
@Bean//登出用
public FilterRegistrationBean filterAuthenticationRegistration() {
FilterRegistrationBean registration = new FilterRegistrationBean();
// AuthenticationFilter 该过滤器负责用户的认证工作
registration.setFilter(new AuthenticationFilter());
// 设定匹配的路径
registration.addUrlPatterns("/*");
Map<String,String> initParameters = new HashMap<String, String>();
initParameters.put("casServerLoginUrl", login_url);
initParameters.put("serverName", server_name);
// 忽略 /logoutSuccess 的路径
initParameters.put("ignorePattern", "/logoutSuccess/*");
registration.setInitParameters(initParameters);
// 设定加载的顺序
registration.setOrder(1);
return registration;
}
}
- 测试接口
@RequestMapping("/test1")
public String test1() {
return "test1....";
}
@RequestMapping("/logout")
public String logout(HttpServletRequest request) {
HttpSession session = request.getSession();
session.invalidate();
return "redirect:http://localhost:8080/cas/logout?service=http://localhost:8088/logoutSuccess";
}
@RequestMapping("/logoutSuccess")
@ResponseBody
public String logoutSuccess() {
return "member logoutSuccess";
}
浏览器访问test1接口自动跳转到cas的登录页面,输入密码后返回结果,浏览器访问logout接口,返回结果logoutSuccess
3.客户端2:8089
除了其端口不一样以外,其余均一致
启动两个客户端,访问登录任一接口,另外一个几口便不需要登录;
登出同理.
4.cas配置JDBC
- 在源码5.3的pom中添加以下依赖,并重新打war包
<dependencies>
<!-- Database Authentication Begin -->
<dependency>
<groupId>org.apereo.cas</groupId>
<artifactId>cas-server-support-jdbc</artifactId>
<version>${cas.version}</version>
</dependency>
<!--自适配数据库驱动,其中包括HSQLDB、Oracle、MYSQL(8)、PostgreSQL、MariaDB、Microsoft SQL Server-->
<dependency>
<groupId>org.apereo.cas</groupId>
<artifactId>cas-server-support-jdbc-drivers</artifactId>
<version>${cas.version}</version>
</dependency>
<!-- Database Authentication End -->
</dependencies>
- 重新打包,并修改application文件
# 兼容 Http 协议
cas.tgc.secure=false
# 开启识别Json文件,默认false
cas.serviceRegistry.initFromJson=true
# 允许退出登录后重定向到其他页面
cas.logout.followServiceRedirects=true
##
# CAS Authentication Credentials
#
#cas.authn.accept.users=casuser::Mellon
#jdbc验证配置
#Query Database Authentication 数据库查询校验用户名开始
#查询账号密码sql,必须包含密码字段
cas.authn.jdbc.query[0].sql=select * from user where name=?
#指定上面的sql查询字段名(必须)
cas.authn.jdbc.query[0].fieldPassword=password
#指定过期字段,1为过期,若过期需要修改密码
#cas.authn.jdbc.query[0].fieldExpired=expired
#为不可用字段段,1为不可用,
#cas.authn.jdbc.query[0].fieldDisabled=disabled
#数据库方言hibernate的知识
cas.authn.jdbc.query[0].dialect=org.hibernate.dialect.MySQLDialect
#数据库驱动
cas.authn.jdbc.query[0].driverClass=com.mysql.cj.jdbc.Driver
#数据库连接
cas.authn.jdbc.query[0].url=jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
#数据库用户名
cas.authn.jdbc.query[0].user=root
#数据库密码
cas.authn.jdbc.query[0].password=123456
#默认加密策略,通过encodingAlgorithm来指定算法,默认NONE不加密
#cas.authn.jdbc.query[0].passwordEncoder.type=com.sso.config.MyPasswordEncoder
cas.authn.jdbc.query[0].passwordEncoder.characterEncoding=UTF-8
#cas.authn.jdbc.query[0].passwordEncoder.encodingAlgorithm=MD5
#Query Database Authentication 数据库查询校验用户名结束
#jdbc验证配置
- 启动客户端,即可.
Oauth2
1.简介
OAuth是一个关于授权(authorization)的开放网络标准,
oauth2根据使用场景不同,分成了4种模式
- 授权码模式(authorization code),最复杂最常用的模式
第一步:【A服务客户端】将用户自动导航到【B服务认证服务】,这一步用户需要提供一个回调地址,以备【B服务认证服务】返回授权码使用。 第二步:用户点击授权按钮表示让【A服务客户端】使用【B服务资源服务】,这一步需要用户登录B服务,也就是说用户要事先具有B服务的使用权限。 第三步:【B服务认证服务】生成授权码,授权码将通过第一步提供的回调地址,返回给【A服务客户端】。( 注意这个授权码并非通行【B服务资源服务】的通行凭证。)
第四步:【A服务认证服务】携带上一步得到的授权码向【B服务认证服务】发送请求,获取通行凭证
token
。 第五步 :【B服务认证服务】给【A服务认证服务】返回令牌token
和更新令牌refresh token
。
- 简化模式(implicit)
第一步:【A服务客户端】将用户自动导航到【B服务认证服务】,这一步用户需要提供一个回调地址,以备【B服务认证服务】返回
token
使用,还会携带一个【A服务客户端】的状态标识state
。 第二步 :用户点击授权按钮表示让【A服务客户端】使用【B服务资源服务】,这一步需要用户登录B服务,也就是说用户要事先具有B服务的使用权限。
第三步:【 B服务认证服务】生成通行令牌
token
,token
将通过第一步提供的回调地址,返回给【A服务客户端】。
- 密码模式(resource owner password credentials)
第一步:直接告诉【A服务客户端】自己的【B服务认证服务】的用户名和密码 第二步 :【A服务客户端】携带【B服务认证服务】的用户名和密码向【B服务认证服务】发起请求获取
token
。 第三步 :【B服务认证服务】给【A服务客户端】颁发token
。
- 客户端模式(client credentials)
第一步:A服务向B服务索取
token
。 第二步:B服务返回token
给A服务。
待续....
SpringSecurity
1.简介
重要的类(SpringSecurity的核心)
- WebSecurityConfigureAdapter: 自定义Security策略
- AuthenticationManagerBuilder: 自定义认证策略
- @EnableWebSecurity: 开启WebSecurity模式
两个核心目标是"认证"和"授权" (访问控制)
认证 ====> Authentication
授权 ====> Authorization
2.依赖
<!--security-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
3.配置类
extends WebSecurityConfigurerAdapter
package zong.config;
import org.springframework.context.annotation.Configuration;
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.crypto.bcrypt.BCryptPasswordEncoder;
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
//链式编程
//授权
@Override
protected void configure(HttpSecurity http) throws Exception {
//首页所有人可以访问, 功能页只有对应有权限的人才能访问
//请求授权的规则
http.authorizeRequests().antMatchers("/").permitAll()//允许所有
.antMatchers("/level1/**").hasRole("role1")//含有level1的需要角色role1
.antMatchers("/level2/**").hasRole("role2")//含有level2的需要角色role2
.antMatchers("/level3/**").hasRole("role3");
//没有权限, 默认回到登录页面(/login), 需要开启登录的页面
http.formLogin();
//自定义登录页面
// http.formLogin().loginPage("/toLogin").loginProcessingUrl("/login");
//注销, 开启了注销功能, 跳到首页
http.logout().deleteCookies("remove").invalidateHttpSession(true).logoutSuccessUrl("/");
//get 明文, a标签, 不安全 post 表单, 安全
//SpringSecurity默认开启了防止csrf攻击的设置, 使用disable可以将其关闭
http.csrf().disable();
//开启记住我功能 cookie 默认保存两周 自定义rememberMe对应的前端的name属性
http.rememberMe().rememberMeParameter("rememberMe");
}
//认证
//密码编码: PassWordEncoding
//在SpringSecurity 5.0+ 新增了很多的加密方式
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//此处的数据正常情况下应该从数据库中读
auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
.withUser("test").password(
new BCryptPasswordEncoder().encode("123456")).roles("role2", "role3")
.and()
.withUser("root").password(
new BCryptPasswordEncoder().encode("123456")).roles("role1", "role2", "role3")
.and()
.withUser("guest").password(
new BCryptPasswordEncoder().encode("123456")).roles("role1");
}
}
4.测试
访问
登录test用户无法访问接口,登录root即可.
5.注解
5.1 配置
Spring Security默认是禁用注解的,要想开启注解,要在继承WebSecurityConfigurerAdapter
的类加@EnableMethodSecurity
注解,并在该类中将AuthenticationManager
定义为Bean。
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true, jsr250Enabled = true)//三种注解,true代表开启
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}
5.2 JSR-250注解
- @DenyAll
- @RolesAllowed > @RolesAllowed({"USER", "ADMIN"})
- @PermitAll
5.3 securedEnabled注解
在方法上指定安全性要求 角色/权限,@Secured对应的角色必须要有ROLE_前缀。
5.4 prePostEnabled注解
- @PreAuthorize --适合进入方法之前验证授权
- @PostAuthorize --检查授权方法之后才被执行
- @PostFilter --在方法执行之后执行,而且这里可以调用方法的返回值,然后对返回值进行过滤或处理或修改并返回
- @PreFilter --在方法执行之前执行,而且这里可以调用方法的参数,然后对参数值进行过滤或处理或修改
5.5 异常处理
@Component
@Slf4j
public class AccessDeniedAuthenticationHandler implements AccessDeniedHandler {
private final ObjectMapper objectMapper;
public AccessDeniedAuthenticationHandler(ObjectMapper objectMapper) {
this.objectMapper = objectMapper;
}
@Override
public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AccessDeniedException e) throws IOException {
log.info("没有权限");
httpServletResponse.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
httpServletResponse.setContentType("application/json;charset=UTF-8");
httpServletResponse.getWriter().write(objectMapper.writeValueAsString(e.getMessage()));
}
}
/*
http.authorizeRequests().anyRequest().authenticated().and().exceptionHandling().accessDeniedHandler(accessDeniedAuthenticationHandler);
*/