|
@@ -0,0 +1,157 @@
|
|
|
+package com.gihon.security.config;
|
|
|
+
|
|
|
+import com.gihon.security.encoder.MyPasswordEncoder;
|
|
|
+import com.gihon.security.handler.MyAccessDeniedHandler;
|
|
|
+import com.gihon.security.handler.MyFailureHandler;
|
|
|
+import com.gihon.security.handler.MySuccessHandler;
|
|
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
|
+import org.springframework.context.annotation.Bean;
|
|
|
+import org.springframework.context.annotation.Configuration;
|
|
|
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
|
|
+import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
|
|
+import org.springframework.security.core.userdetails.UserDetailsService;
|
|
|
+import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
|
|
+import org.springframework.security.crypto.password.PasswordEncoder;
|
|
|
+import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
|
|
|
+import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;
|
|
|
+
|
|
|
+import javax.sql.DataSource;
|
|
|
+
|
|
|
+/**
|
|
|
+ * SpringSecurity的配置类型
|
|
|
+ * 继承父类型WebSecurityConfigurerAdapter
|
|
|
+ * WebSecurityConfigurerAdapter是一个Security提供的配置模板,可以快速实现
|
|
|
+ * Security配置,简化自定义配置的复杂度。
|
|
|
+ *
|
|
|
+ * SpringSecurity提供的默认环境,如:登录页面、登录处理请求(/login)、拦截处理(未登录访问其他地址自动跳转到登录页面)
|
|
|
+ * 只有在不提供自定义Security配置的时候,才有效。
|
|
|
+ *
|
|
|
+ * Security要求自定义的UserDetailsService配置配套提供一个PasswordEncoder类型的对象,
|
|
|
+ * 对象中提供密码的加密和匹配逻辑,为认证提供加密处理。
|
|
|
+ * 如果spring环境中没有PasswordEncoder类型的对象,UserDetailsService类型的对象无效。
|
|
|
+ */
|
|
|
+@Configuration
|
|
|
+public class MySecurityConfiguration extends WebSecurityConfigurerAdapter {
|
|
|
+ /**
|
|
|
+ * 在Security中,处理认证逻辑的具体代码,不需要提供控制器逻辑。
|
|
|
+ * 因为Security根据配置formLogin().loginProcessingUrl()自动做控制跳转。
|
|
|
+ * 跳转逻辑是:
|
|
|
+ * 找UserDetailsService接口的实现类型对象,调用启动的方法loadUserByUsername,实现登录认证。
|
|
|
+ * @param http
|
|
|
+ * @throws Exception
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ protected void configure(HttpSecurity http) throws Exception {
|
|
|
+ // 设置登录页面路径地址是 '/'
|
|
|
+ http.formLogin() // 获取Security中专门用来配置登录相关逻辑的配置类型
|
|
|
+ .usernameParameter("name") // 设置请求参数中,用户名的参数名称
|
|
|
+ .passwordParameter("pswd") // 设置请求参数中,密码的参数名称
|
|
|
+ .loginPage("/") // 配置登录页面请求地址是什么。
|
|
|
+ .loginProcessingUrl("/login") // 使用POST访问,访问什么地址的时候,实现认证逻辑。登录地址。
|
|
|
+ // 认证成功或失败,Security会转发请求,到指定的地址。转发的请求是POST方式的。需要定义控制器处理。
|
|
|
+ // .successForwardUrl("/success") // 登录成功后,跳转地址。 请求转发, 重复登录。
|
|
|
+ // .defaultSuccessUrl("/success") // 登录成功后,重定向到指定位置
|
|
|
+ .successHandler(new MySuccessHandler("/sso/success")) // 登录成功后,自定义处理逻辑。
|
|
|
+ // .failureForwardUrl("/fail"); // 登录失败后,跳转地址
|
|
|
+ // .failureUrl("/fail"); // 登录失败后,响应重定向
|
|
|
+ .failureHandler(new MyFailureHandler("/sso/fail")); // 登录失败后,自定义处理逻辑
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 设置权限相关
|
|
|
+ * 可以通过对ExpressionUrlAuthorizationConfigurer配置,实现对URL地址的权限管理。
|
|
|
+ * 可以定义针对固定地址、表达式地址的权限控制。
|
|
|
+ * 常用权限控制方法:
|
|
|
+ * 1、 permitAll() - 全权限访问,任意客户端都可访问。
|
|
|
+ * 2、 authenticated() - 必须认证后才能访问。登录后才能访问。
|
|
|
+ * 3、 denyAll() - 无访问权限。 没有登录的时候,要求登录;登录后,显示403无访问权限错误。
|
|
|
+ * 4、 anonymous() - 匿名访问。可以不登录就访问的资源。和permitAll类似。
|
|
|
+ * 5、 rememberMe() - 记住我。当认证的时候,开启了rememberMe功能,可以使用记住我访问。
|
|
|
+ * 6、 fullyAuthenticated() - 完整认证才可访问。 rememberMe不能访问。
|
|
|
+ *
|
|
|
+ * 联合使用:
|
|
|
+ * 如: antMatchers("/", "/index").permitAll(); 请求 "/" 或 "/index" 的时候,授予所有权限。
|
|
|
+ * 基于角色和权限的访问控制:
|
|
|
+ * 必须建立在已认证的基础上,才会执行对应的访问控制。
|
|
|
+ * 1、 基于角色的访问控制:
|
|
|
+ * URL匹配().hasRole | hasAnyRole
|
|
|
+ * hasRole(String role) - 判断已登录的用户权限集合中,是否包含参数角色
|
|
|
+ * 底层是调用的access("hasRole('ROLE_"+role+"')")
|
|
|
+ * hasAnyRole(String... roles) - 判断已登录的用户权限集合中,是否包括参数中的任意角色。
|
|
|
+ * 底层是调用的access("hasAnyRole('ROLE_角色1','ROLE_角色2'....)")
|
|
|
+ * 2、 基于权限的访问控制:
|
|
|
+ * hasAuthority(String authority) - 判断已登录的用户权限集合中,是否包含权限
|
|
|
+ * 底层: access("hasAuthority('权限')")
|
|
|
+ * hasAnyAuthority(String... authorities) - 判断已登录的用户权限集合中,是否包含参数中任意权限
|
|
|
+ * 底层: access("hasAnyAuthority('权限1','权限2'....)")
|
|
|
+ * 3、 基于IP的访问控制:
|
|
|
+ * hasIpAddress(String ipAddress) 检查客户端IP是否是参数指定的IP
|
|
|
+ * 客户端IP是: HttpServletRequest.getRemoteAddr()方法的返回值。
|
|
|
+ * 底层: access("hasIpAddress('IP地址')")
|
|
|
+ */
|
|
|
+ http.authorizeRequests() // 获取Security中专门配置权限管理的配置类型
|
|
|
+ .antMatchers("/", "/fail").permitAll() // 访问 '/' 地址的时候,不需要登录。
|
|
|
+ .antMatchers("/**/*.js").permitAll() // 只处理js文件
|
|
|
+ .regexMatchers(".+[.]css").permitAll() // 只处理css
|
|
|
+// .antMatchers("/anonymous").anonymous() // 匿名访问
|
|
|
+// .antMatchers("/denyAll").denyAll() // 不能访问
|
|
|
+// .antMatchers("/hasAdminRole").hasRole("管理员") // 判断有没有"管理员"角色
|
|
|
+// .antMatchers("/hasUserRole").hasRole("普通用户") // 判断有没有"普通用户"角色
|
|
|
+// .antMatchers("/hasAnyRole").hasAnyRole("管理员", "普通用户") // 判断是否包含管理员或普通用户角色。
|
|
|
+// .antMatchers("/hasAuthority").hasAuthority("userManagement")
|
|
|
+// .antMatchers("/hasAnyAuthority").hasAnyAuthority("userManagement","selfManagement")
|
|
|
+// .antMatchers("/accessRole").access("hasRole('ROLE_管理员')")// 使用access,角色控制
|
|
|
+// .antMatchers("/accessAuthority").access("hasAuthority('selfManagement')")// 使用access,权限控制
|
|
|
+ // WebSecurityExpressionRoot
|
|
|
+// .antMatchers("/*").access("@myPermissionsMatcherImpl.hasPermission(request,authentication)")
|
|
|
+ .anyRequest().authenticated(); // 所有的请求地址,都必须登录才能访问。
|
|
|
+
|
|
|
+ // 异常处理配置
|
|
|
+ http.exceptionHandling().accessDeniedHandler(new MyAccessDeniedHandler());
|
|
|
+
|
|
|
+ // 配置rememberMe, 使用rememberMe功能的时候,认证成功结果跳转,一定要使用重定向。
|
|
|
+ http.rememberMe()
|
|
|
+ .rememberMeParameter("rememberMe") // 设置请求参数名,默认为remember-me
|
|
|
+ .rememberMeCookieName("rememberMe") // 设置记住我的cookie名称。默认为remember-me
|
|
|
+ .tokenValiditySeconds(300) // 设置rememberMe有效时长。默认14天。
|
|
|
+ .userDetailsService(userLoginServiceImpl) // 设置用户认证逻辑对象
|
|
|
+ .tokenRepository(tokenRepository); // 设置rememberMe数据持久化对象。持久化用户认证成功后的主体。
|
|
|
+
|
|
|
+ // 退出配置, 注销配置
|
|
|
+ http.logout()
|
|
|
+ .invalidateHttpSession(true) // 退出的时候,销毁HttpSession对象。默认true
|
|
|
+ .clearAuthentication(true) // 退出的时候,清空已认证用户主体对象。默认true
|
|
|
+ .logoutUrl("/logout") // 退出登录的请求地址。默认是 /logout
|
|
|
+ .logoutSuccessUrl("/"); // 退出后的跳转地址,重定向。 默认是 loginPage?logout
|
|
|
+
|
|
|
+ // csrf安全处理, 关闭csrf。 防止恶意攻击的技术。 security4+ 默认开启的。
|
|
|
+ // http.csrf().disable();
|
|
|
+ }
|
|
|
+
|
|
|
+// @Autowired
|
|
|
+// private DataSource dataSource;
|
|
|
+
|
|
|
+ // rememberMe数据保存对象,相当于是DAO
|
|
|
+ @Bean
|
|
|
+ public PersistentTokenRepository persistentTokenRepository(DataSource dataSource){
|
|
|
+ // 使用Spring-JDBC技术,实现rememberMe数据的存储。保存到数据库。
|
|
|
+ // 在JdbcTokenRepositoryImpl类型的对象中,必须提供一个DataSource对象。
|
|
|
+ JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl();
|
|
|
+ jdbcTokenRepository.setDataSource(dataSource);
|
|
|
+ // rememberMe表格的创建, 只能在系统第一次启动的时候创建。 默认是false,不会启动创建表格。
|
|
|
+ // jdbcTokenRepository.setCreateTableOnStartup(true);
|
|
|
+
|
|
|
+ return jdbcTokenRepository;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private UserDetailsService userLoginServiceImpl;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private PersistentTokenRepository tokenRepository;
|
|
|
+
|
|
|
+ // 传递的构造参数BCryptPasswordEncoder(int strength), 建议为8的整数倍。
|
|
|
+ @Bean
|
|
|
+ public PasswordEncoder passwordEncoder(){
|
|
|
+ return new MyPasswordEncoder();
|
|
|
+ }
|
|
|
+}
|