当前位置:
首页 > temp > 简明python教程 >
-
Java框架之SpringSecurity 08-权限系统
SpringSecurity
SpringSecurity融合Spring技术栈,提供JavaEE应用的整体安全解决方案;提供全面的安全服务。Spring Security支持广泛的认证模型模块划分
Core - spring-security-core.jar | 核心模块:核心认证、授权功能、支持jdbc-user功能、支持独立的Spring应用 |
Remoting - spring-security-remoting.jar | 远程交互模块:一般不需要,可以使用Spring Remoting功能简化远程客户端交互 |
Web - spring-security-web.jar | web安全模块:web项目使用,基于URL的访问控制(access-control) |
Config - spring-security-config.jar | java配置模块:必须依赖包,包含解析xml方式和java 注解方式来使用SpringSecurity功能 |
LDAP - spring-security-ldap.jar | ldap(轻量目录访问协议)支持模块:可选依赖包,LDAP功能支持 |
ACL - spring-security-acl.jar | ACL支持:ACL(Access-Control-List)访问控制列表。细粒度的资源访问控制(RBAC+ACL) |
CAS - spring-security-cas.jar | CAS整合支持:CAS(Central Authentication Service)中央认证服务。开源ApereoCAS整合 |
OpenID - spring-security-openid.jar | OpenID 认证方式: 用于针对外部服务器对用户进行身份验证(微信,新浪微博第三方登录) |
Test - spring-security-test.jar | 测试模块:快速的测试SpringSecurity应用 |
基于Maven Web工程实例
添加 security-pom 依赖<!-- 安全框架中的jar包 --> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-web</artifactId> <version>4.2.10.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-config</artifactId> <version>4.2.10.RELEASE</version> </dependency> <!-- 标签库 --> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-taglibs</artifactId> <version>4.2.10.RELEASE</version> </dependency>
<!-- 核心控制器,注意需将spring及springmvc配置文件都由Web容器装载 --> <servlet> <servlet-name>springDispatcherServlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value> classpath*:/spring/springmvc.xml classpath*:/spring/spring-*.xml </param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <!--代理管理所有 SpringSecurity 过滤器--> <filter> <filter-name>springSecurityFilterChain</filter-name><!--名称固定,不能变--> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> </filter> <filter-mapping> <filter-name>springSecurityFilterChain</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
/** * @Configuration 管理程序中的组件(扫描) * @EnableWebSecurity 安全框架支持注解的形式 基础注解 * @EnableGlobalMethodSecurity 开启使用表达式方法验证安全性 */ @Configuration @EnableWebSecurity @EnableGlobalMethodSecurity(prePostEnabled = true) public class AppWebSecurityConfig extends WebSecurityConfigurerAdapter { @Override //认证 protected void configure(AuthenticationManagerBuilder auth) throws Exception { } @Override //授权 protected void configure(HttpSecurity http) throws Exception { } }
l 令牌值变化:
n 如果登录成功(用户名,密码正确),令牌会被删除,
n 重新回到登录页或后退网页,令牌会重新生成;
n 如果登录失败(用户名,密码错误),令牌不变。
n 刷新登录页,令牌值也不变
认证
@Autowired private UserDetailsService userDetailsService; @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { //从数据库中查询数据 auth.userDetailsService(userDetailsService).passwordEncoder(new BCryptPasswordEncoder()); }
UserDetailsService
此接口由 Security 来调用基于 AOP 模式进行权限检查,返回一个 UserDetails 接口类型其存放着该用户从数据库查询出来的所有权限信息步骤: 1 在业务层实现 UserDetailsService 接口通过用户名从 Dao 层查询出该用户对象 2 创建一个 HashSet<GrantedAuthority> 接口类型的集合,该 GrantedAuthority 类型用来存放角色和权限信息,它的实现类 SimpleGrantedAuthority 需要传入字符串类型角色名和权限名 3 通过该用户 id 查询出该用户所拥有的角色集合 4 通过该用户 id 查询出该用户所拥有的权限集合 5 通过所有角色名和所有权限名 创建 SimpleGrantedAuthority 对象并添加到 HashSet<GrantedAuthority> 集合中 6 创建 User 类对象,该对象实现了 UserDetails 接口,为此 user 对象传入该用户的用户名和密码加上权限集合 Set 并返回该对象即可
@Autowired //用户 private TAdminMapper adminMapper; @Autowired //角色 private TRoleMapper roleMapper; @Autowired //权限 private TPermissionMapper permissionMapper; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { TAdminExample example = new TAdminExample(); TAdminExample.Criteria criteria = example.createCriteria(); criteria.andLoginacctEqualTo(username); List<TAdmin> admins = adminMapper.selectByExample(example); //从数据库中查出该用户 TAdmin admin = admins.get(0); //该集合用来存放角色和权限 HashSet<GrantedAuthority> authorities = new HashSet<>(); //从数据库中查出该用户所对应的角色 List<TRole> roles = roleMapper.listRole(admin.getId()); //从数据库中查出该用户所对应的权限 List<TPermission> permissions = permissionMapper.listPermission(admin.getId()); //分别将角色和权限添加到 authorities 集合中 for (TRole role : roles) { String name = role.getName(); authorities.add(new SimpleGrantedAuthority("ROLE_" + name));//注意角色需加上 "ROLE_" } permissions.forEach((p) -> { String name = p.getName(); authorities.add(new SimpleGrantedAuthority(name)); }); //通过该用户名和密码以及权限集合创建User对象并返回 User user = new User(admin.getLoginacct().toString(), admin.getUserpswd().toString(), authorities); return user; }
授权
HttpSecurity 该类允许对特定的http请求基于安全考虑进行配置。默认情况下,适用于所有的请求.亦通过该对象 http 方法为用户配置精细化权限访问控制@Override protected void configure(HttpSecurity http) throws Exception { //基于httpRequest对指定antMatchers资源permitAll放行,对于其他请求anyRequest必须通过认证authenticated http.authorizeRequests().antMatchers("/welcome.jsp","/static/**") .permitAll().anyRequest().authenticated(); //跳转到默认登录界面 http.formLogin().loginPage("/welcome.jsp"); //登录时指定的控制器/login,并验证用户名和密码,成功验证后跳转到控制器/main http.formLogin().loginProcessingUrl("/login") .usernameParameter("loginacct") .passwordParameter("userpswd") .defaultSuccessUrl("/main"); //取消csrf令牌值验证 http.csrf().disable(); //退出时指定的控制器,并指定成功退出后登录界面 http.logout().logoutUrl("/exit").logoutSuccessUrl("/welcome.jsp"); //记住我功能.需在前端复选框中指定 value 值为 remember-me http.rememberMe(); //自定义的异常处理器 http.exceptionHandling().accessDeniedHandler(new AccessDeniedHandler() { @Override public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException { //判断是否为异步请求 if("XMLHttpRequest".equals(request.getHeader("X-Requested-With"))){ response.getWriter().write("403"); }else { request.setAttribute("msg",accessDeniedException.getMessage()); request.getRequestDispatcher("/WEB-INF/views/unauth.jsp") .forward(request,response); } } }); }
authorizeRequests():返回一个配置对象用于配置请求的访问限制
formLogin():返回表单配置对象,当什么都不指定时会提供一个默认的,如配置登录请求,还有登录成功页面
logout():返回登出配置对象,可通过logoutUrl设置退出url
antMatchers:匹配请求路径或请求动作类型,如:.antMatchers("/admin/**")
addFilterBefore: 在某过滤器之前添加 filter
addFilterAfter:在某过滤器之后添加 filter
addFilterAt:在某过滤器相同位置添加 filter,不会覆盖相同位置的 filter
hasRole:结合 antMatchers 一起使用,设置请求允许访问的角色权限或IP
方法名 | 用途 |
access(String) | SpringEL表达式结果为true时可访问 |
anonymous() | 匿名可访问 |
denyAll() | 用户不可以访问 |
fullyAuthenticated() | 用户完全认证访问(非remember me下自动登录) |
hasAnyAuthority(String…) | 参数中任意权限可访问 |
hasAnyRole(String…) | 参数中任意角色可访问 |
hasAuthority(String) | 某一权限的用户可访问 |
hasRole(String) | 某一角色的用户可访问 |
permitAll() | 所有用户可访问 |
rememberMe() | 允许通过remember me登录的用户访问 |
authenticated() | 用户登录后可访问 |
hasIpAddress(String) | 用户来自参数中的IP可访问 |
@EnableGlobalMethodSecurity详解
@EnableGlobalMethodSecurity(securedEnabled=true) 开启@Secured 注解过滤权限
@Secured("软件工程师") :拥有指定角色才可以访问方法
@EnableGlobalMethodSecurity(jsr250Enabled=true)开启@RolesAllowed 注解过滤权限
@EnableGlobalMethodSecurity(prePostEnabled=true) 使用 SpEL 表达式方法级别的安全性 4个注解可用
@Secured("软件工程师") :拥有指定角色才可以访问方法
@EnableGlobalMethodSecurity(jsr250Enabled=true)开启@RolesAllowed 注解过滤权限
@EnableGlobalMethodSecurity(prePostEnabled=true) 使用 SpEL 表达式方法级别的安全性 4个注解可用
@PreAuthorize 在方法执行之前检查,基于表达式的计算结果来限制对方法的访问 //@PreAuthorize("hasRole('软件工程师')")
@PostAuthorize 在方法执行后检查,但是如果表达式计算结果为false,将抛出一个安全性异常
@PostFilter 允许方法调用,但必须按照表达式来过滤方法的结果
@PreFilter 允许方法调用,但必须在进入方法之前过滤输入值
Security 标签
在 jsp 页面还可通过标签进一步控制 html 标签的访问权限或获取该用户信息 : 引入标签库<%@taglib prefix="sec" uri="http://www.springframework.org/security/tags" %> <sec:authentication property="name"/> //在需要位置显示用户登录名, 属性 property 必须是 name <sec:authorize access="hasRole('PM - 项目经理')">//非此角色用户隐藏下面的标签 <button type="button" id="deleteBath" class="btn btn-danger" style="float:right;margin-left:10px;">删除</button> </sec:authorize>
栏目列表
最新更新
nodejs爬虫
Python正则表达式完全指南
爬取豆瓣Top250图书数据
shp 地图文件批量添加字段
爬虫小试牛刀(爬取学校通知公告)
【python基础】函数-初识函数
【python基础】函数-返回值
HTTP请求:requests模块基础使用必知必会
Python初学者友好丨详解参数传递类型
如何有效管理爬虫流量?
2个场景实例讲解GaussDB(DWS)基表统计信息估
常用的 SQL Server 关键字及其含义
动手分析SQL Server中的事务中使用的锁
openGauss内核分析:SQL by pass & 经典执行
一招教你如何高效批量导入与更新数据
天天写SQL,这些神奇的特性你知道吗?
openGauss内核分析:执行计划生成
[IM002]Navicat ODBC驱动器管理器 未发现数据
初入Sql Server 之 存储过程的简单使用
SQL Server -- 解决存储过程传入参数作为s
关于JS定时器的整理
JS中使用Promise.all控制所有的异步请求都完
js中字符串的方法
import-local执行流程与node模块路径解析流程
检测数据类型的四种方法
js中数组的方法,32种方法
前端操作方法
数据类型
window.localStorage.setItem 和 localStorage.setIte
如何完美解决前端数字计算精度丢失与数