Spring Security
-
认证和授权
用户登录要进行认证。
用户进行增删改查具体的操作,要进行授权。
-
实现功能
-
用户认证授权信息【通过实现UserDetailsService接口】返回一个User对象(封装了authorities[权限])。
/* 在login时Spring Security会调用该方法,并将用户名自动传入到方法中。 */ @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { //根据用户名查询Admin对象。 Admin admin = adminService.getByUsername(username); if(null == admin) { throw new UsernameNotFoundException("用户名不存在!"); } //获取权限的编码,给用户授权。 //获取用户应该有的权限 List<String> codeList = permissionService.findCodeListByAdminId(admin.getId()); //获取权限的集合。 Collection<GrantedAuthority> authorities = new ArrayList<>(); for(String code : codeList) { if(StringUtils.isEmpty(code)) continue; SimpleGrantedAuthority authority = new SimpleGrantedAuthority(code); authorities.add(authority); } // return new User(username,admin.getPassword(),authorities); }
PermissionService:获取权限列表
@Override public List<String> findCodeListByAdminId(Long adminId) { //超级管理员admin账号id为:1 if(adminId.longValue() == 1) { return permissionDao.findAllCodeList(); } return permissionDao.findCodeListByAdminId(adminId); }
-
实现用户授权,也就是只有授权后才可以使用该功能。
-
开启Controller方法权限控制
WebSecurityConfig的类上加@EnableGlobalMethodSecurity注解, 来判断用户对某个控制层的方法是否具有访问权限
@EnableGlobalMethodSecurity(prePostEnabled = true)
之后在Controller方法上添加注解
//只有当有这个权限码时,才可以使用这个方法。 @PreAuthorize("hasAuthority('role.show')") @RequestMapping public String index(ModelMap model, HttpServletRequest request) { Map<String,Object> filters = getFilters(request); PageInfo<Role> page = roleService.findPage(filters); model.addAttribute("page", page); model.addAttribute("filters", filters); return PAGE_INDEX; }
-
开启按钮权限控制
直接调用Spring Security的标签库即可。需要开启标签支持以及Jar包导入
<!-- 添加spring security 标签支持:sec --> <property name="additionalDialects"> <set> <bean class="org.thymeleaf.extras.springsecurity5.dialect.SpringSecurityDialect" /> </set> </property>
只有在有权限时,按钮才可用。
<a class="edit" th:attr="data-id=${item.id}" sec:authorize="hasAuthority('role.edit')">修改</a> <a class="delete" th:attr="data-id=${item.id}" sec:authorize="hasAuthority('role.delete')">删除</a> <a class="assgin" th:attr="data-id=${item.id}" sec:authorize="hasAuthority('role.assgin')">分配权限</a>
-
-
使用指定的登录页面进行登录。【WebSecurity实现】
-
配置可以访问的静态资源。【WebSecurity实现】
-
对密码进行加密。【WebSecurity实现 + admin新增用户时实现】
//WebSecurity中,我们制定了BCryptPasswordEncoder 密码加密器进行加密和校验,所以我们密码必须要在加密后进行存储。这样才能匹配成功。所以admin在实现新增用户时,我们要给admin密码进行加密。 @Bean public PasswordEncoder passwordEncoder(){ return new BCryptPasswordEncoder(); }
-
-
WebSecurity
添加依赖,配置Filter,配置Spring Security三个步骤,就可以集成使用Spring Security。
在使用Spring Security之前,需要配置,这里使用Java类配置的方法。
@Configuration //声明当前类是一个配置类 @EnableWebSecurity //@EnableWebSecurity是开启SpringSecurity的默认行为 @EnableGlobalMethodSecurity(prePostEnabled = true) public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { //允许iframe嵌套显示 http.headers().frameOptions().disable(); //登录设置 http .authorizeRequests() .antMatchers("/static/**","/login").permitAll() //允许匿名用户访问的路径 .anyRequest().authenticated() // 其它页面全部需要验证 .and() .formLogin() .loginPage("/login") //用户未登录时,访问任何需要权限的资源都转跳到该路径,即登录页面,此时登陆成功后会继续跳转到第一次访问的资源页面(相当于被过滤了一下) .defaultSuccessUrl("/") //登录认证成功后默认转跳的路径,意思时admin登录后也跳转到/user .and() .logout() .logoutUrl("/logout") //退出登陆的路径,指定spring security拦截的注销url,退出功能是security提供的 .logoutSuccessUrl("/login")//用户退出后要被重定向的url .and() //因为Spring Security登录页面是有一个token字符串的,来标识一个网页,如果不关闭,就没有这个token(身份验证令牌)。就会在logout时报错。 // .csrf().disable();//关闭跨域请求伪造功能 //添加自定义异常入口 http.exceptionHandling().accessDeniedHandler(new CustomAccessDeineHandler()); } /** * 必须指定加密方式,上下加密方式要一致 * @return */ @Bean public PasswordEncoder passwordEncoder(){ return new BCryptPasswordEncoder(); } }
-
友好提示
用户没有权限直接返回404吗?不是,这里自定义异常处理,使用AccessDeniedHandler,返回一个错误页面,更友好。
AccessDeniedHandler 该类用来统一处理
AccessDeniedException
异常(主要是在用户在访问受保护资源时被拒绝而抛出的异常)//添加自定义异常入口 http.exceptionHandling().accessDeniedHandler(new CustomAccessDeineHandler()); /** * 未授权的统一处理方式 * */ public class CustomAccessDeineHandler implements AccessDeniedHandler { @Override public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException { response.sendRedirect("/auth"); } }
-