当前位置:   article > 正文

SpringBoot集成Security实现权限控制_springboot security权限控制

springboot security权限控制

SpringSecurity简介

认证+授权

主要有两个主要功能:“认证”,是建立一个他声明的主体的过程(一个“主体”一般是指用户,设备或一些可以在你的应用程序中执行动作的其他系统),通俗点说就是系统认为用户是否能登录。一般在拦截器中进行拦截用户信息进行认证。 “授权"指确定一个主体是否允许在你的应用程序执行一个动作的过程,一般是在Security中进行接口权限配置,查看用户是否具有对应接口权限。通俗点讲就是系统判断用户是否有权限去做某些事情。

相应语法:

.successForwardUrl()登录成功后跳转地址

.loginPage()登录页面

.loginProcessingurl登录页面表单提交地址,此地址可以不真实存在。

antMatchers():匹配内容permitAll():允许

1. 添加依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>

2. 认证

SpringSecurty提供了多种验证方法,本次采用用户名/密码的方式进行验证。所以需要实现UserDetailsService接口中的loadUserByUserName方法,从数据库中查找对应的数据然后与用户输入数据进行对比,所以需要返回一个UserDetails对象。

2.1. 实现UserDetails和UserDetailsService接口

本项目中使用student作为用户表,同时使用type作为权限标识

2.1.1 将student用户类继承UserDetails接口

  1. import com.baomidou.mybatisplus.annotation.IdType;
  2. import com.baomidou.mybatisplus.annotation.TableId;
  3. import lombok.Data;
  4. import lombok.EqualsAndHashCode;
  5. import lombok.experimental.Accessors;
  6. import org.springframework.security.core.GrantedAuthority;
  7. import org.springframework.security.core.userdetails.UserDetails;
  8. import java.util.ArrayList;
  9. import java.util.Collection;
  10. import java.util.Date;
  11. import java.util.List;
  12. @Data
  13. @EqualsAndHashCode(callSuper = false)
  14. @Accessors(chain = true)
  15. public class Student implements UserDetails {
  16. @TableId(value = "id", type = IdType.AUTO)
  17. private Integer id;
  18. private String studentName;
  19. private String studentSex;
  20. private String studentSubject;
  21. private String username;
  22. private String password;
  23. private String salt;
  24. private String email;
  25. private Integer type;
  26. private Integer status;
  27. private String activationCode;
  28. private String headerUrl;
  29. private Date createTime;
  30. private String studentPhone;
  31. // true: 账号未过期.
  32. @Override
  33. public boolean isAccountNonExpired() {
  34. return true;
  35. }
  36. // true: 账号未锁定.
  37. @Override
  38. public boolean isAccountNonLocked() {
  39. return true;
  40. }
  41. // true: 凭证未过期.
  42. @Override
  43. public boolean isCredentialsNonExpired() {
  44. return true;
  45. }
  46. // true: 账号可用.
  47. @Override
  48. public boolean isEnabled() {
  49. return true;
  50. }
  51. @Override
  52. public Collection<? extends GrantedAuthority> getAuthorities() {
  53. List<GrantedAuthority> list = new ArrayList<>();
  54. list.add(new GrantedAuthority() {
  55. @Override
  56. public String getAuthority() {
  57. switch (type) {
  58. case 1:
  59. return "ADMIN";
  60. default:
  61. return "USER";
  62. }
  63. }
  64. });
  65. return list;
  66. }
  67. }

2.1.2 同时StudentService继承UserDetailsService

创建getAuthorities方法 获取用户权限,同时Type的字段值代表了用户的权限

自定义实现验证权限类型

  1. public interface StudentService extends IService<Student>, UserDetailsService {
  2. Collection<? extends GrantedAuthority> getAuthorities(Integer id);
  3. }
  1. @Service
  2. public class StudentServiceImpl extends ServiceImpl<StudentMapper, Student> implements StudentService {
  3. @Override
  4. public Collection<? extends GrantedAuthority> getAuthorities(Integer id) {
  5. Student student = this.findStudentById(id);
  6. List<GrantedAuthority> list = new ArrayList<>();
  7. list.add(new GrantedAuthority() {
  8. @Override
  9. public String getAuthority() {
  10. switch (student.getType()) {
  11. case 1:
  12. return AUTHORITY_ADMIN;
  13. case 2:
  14. return AUTHORITY_MODERATOR;
  15. default:
  16. return AUTHORITY_USER;
  17. }
  18. }
  19. });
  20. return list;
  21. }
  22. }

2.2 创建CommunityConstant接口返回权限类型

可以自定义也可以不使用这一步

  1. public interface CommunityConstant {
  2. /**
  3. 权限:普通用户ID
  4. **/
  5. String AUTHORITY_USER="user";
  6. /**
  7. 权限:管理员ID
  8. **/
  9. String AUTHORITY_ADMIN="admin";
  10. /**
  11. 权限:管理员ID
  12. **/
  13. String AUTHORITY_MODERATOR="moderator";
  14. }

2.3 认证步骤

将student中的用户信息导入到Security中,使得安全配置生效

//构建用户认证结果,并存入SecurityContext,以便于Security进行授权
                Authentication authentication=new UsernamePasswordAuthenticationToken(
                        student,student.getPassword(),studentService.getAuthorities(student.getId()));

                SecurityContextHolder.setContext(new SecurityContextImpl(authentication));

本次采用拦截器的形式来进行构建用户认证结果,并存入SecurityContext,以便于Security进行授权,如果loadUserByName验证通过,则此处没有问题,即可验证通过。

  1. @Component
  2. public class LoginInterceptor implements HandlerInterceptor {
  3. @Autowired
  4. private HostHolder hostHolder;
  5. @Autowired
  6. private StudentService studentService;
  7. @Override
  8. public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
  9. String ticket = CookieUtil.getValue(request, "ticket"); //调用存在cookie里的数据
  10. if (ticket != null) {
  11. // 查询凭证
  12. LoginTicket loginTicket = studentService.findLoginTicket(ticket);
  13. // 检查凭证是否有效
  14. if (loginTicket != null && loginTicket.getStatus() == 0 && loginTicket.getExpired().after(new Date())) {
  15. // 根据凭证查询用户
  16. Student student = studentService.findStudentById(loginTicket.getUserId());
  17. // 在本次请求中持有用户
  18. hostHolder.setStudent(student);
  19. //构建用户认证结果,并存入SecurityContext,以便于Security进行授权
  20. Authentication authentication=new UsernamePasswordAuthenticationToken(
  21. student,student.getPassword(),studentService.getAuthorities(student.getId()));
  22. SecurityContextHolder.setContext(new SecurityContextImpl(authentication));
  23. return true;
  24. }else{
  25. response.sendRedirect(request.getContextPath()+"/login"); //转发请求 到request.getContextPath() + "/login";
  26. }
  27. }else {
  28. response.sendRedirect(request.getContextPath()+"/login"); //request.getContextPath()为请求目录 localhost:8080/sushe/
  29. }
  30. return false;
  31. }
  32. @Override
  33. public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
  34. Student student = hostHolder.getStudent();
  35. if (student != null && modelAndView != null) {
  36. modelAndView.addObject("loginStudent", student);
  37. }
  38. }
  39. @Override
  40. public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
  41. hostHolder.clear();
  42. }
  43. }

3. 授权

在认证通过之后我们可以在security配置中进行用户,管理员等不同角色对接口的访问限制。

.antMatcher{}  对应相关接口

.hasAnyAuthority{} 对应相关用户

  1. package com.example.sushe.config;
  2. import com.example.sushe.util.CommunityConstant;
  3. import com.example.sushe.util.CommunityUtil;
  4. import org.springframework.context.annotation.Configuration;
  5. import org.springframework.security.access.AccessDeniedException;
  6. import org.springframework.security.config.annotation.web.builders.HttpSecurity;
  7. import org.springframework.security.config.annotation.web.builders.WebSecurity;
  8. import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
  9. import org.springframework.security.core.AuthenticationException;
  10. import org.springframework.security.web.AuthenticationEntryPoint;
  11. import org.springframework.security.web.access.AccessDeniedHandler;
  12. import javax.servlet.ServletException;
  13. import javax.servlet.http.HttpServletRequest;
  14. import javax.servlet.http.HttpServletResponse;
  15. import java.io.IOException;
  16. import java.io.PrintWriter;
  17. @Configuration
  18. public class SecurityConfig extends WebSecurityConfigurerAdapter implements CommunityConstant {
  19. @Override
  20. public void configure(WebSecurity web) throws Exception {
  21. web.ignoring().antMatchers("/resources/**");
  22. }
  23. @Override
  24. protected void configure(HttpSecurity http) throws Exception {
  25. //授权
  26. http.authorizeRequests()
  27. .antMatchers(
  28. "/person/findAll"
  29. )
  30. .hasAnyAuthority(
  31. AUTHORITY_USER,
  32. AUTHORITY_ADMIN,
  33. AUTHORITY_MODERATOR
  34. )
  35. .antMatchers(
  36. "/person/add/*","/person/update/*","/person/updatePerson","/person/delete","/subject/*"
  37. )
  38. .hasAnyAuthority(
  39. AUTHORITY_ADMIN
  40. )
  41. .anyRequest().permitAll()
  42. .and().csrf().disable();
  43. //权限不够时的出理
  44. http.exceptionHandling()
  45. .authenticationEntryPoint(new AuthenticationEntryPoint() {
  46. //没有登陆
  47. @Override
  48. public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) throws IOException, ServletException {
  49. String xRequestedWith = request.getHeader("x-requested-with");
  50. if("XMLHttpRequest".equals(xRequestedWith)){
  51. response.setContentType("application/plain/character=utf-8");
  52. PrintWriter writer=response.getWriter();
  53. writer.write((CommunityUtil.getJSONString(403,"你还没有登录呕")));
  54. }else{
  55. response.sendRedirect(request.getContextPath()+"/login");
  56. }
  57. }
  58. })
  59. .accessDeniedHandler(new AccessDeniedHandler() {
  60. //权限不足
  61. @Override
  62. public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException e) throws IOException, ServletException {
  63. String xRequestedWith = request.getHeader("x-requested-with");
  64. if("XMLHttpRequest".equals(xRequestedWith)){
  65. response.setContentType("application/plain/character=utf-8");
  66. PrintWriter writer=response.getWriter();
  67. writer.write((CommunityUtil.getJSONString(403,"没有访问此页面的权限")));
  68. }else{
  69. response.sendRedirect(request.getContextPath()+"/error");
  70. }
  71. }
  72. });
  73. //Security底层会默认拦截/logout请求,进行退出处理
  74. //覆盖它原来的逻辑
  75. http.logout().logoutUrl("/Securitylogout");
  76. }
  77. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/码创造者/article/detail/774488
推荐阅读
相关标签
  

闽ICP备14008679号