当前位置:   article > 正文

SpringSecurity安全框架_spring安全框架

spring安全框架

目录

一、Spring Security介绍

1、框架介绍

2、认证与授权实现思路

二、整合Spring Security

1、在common下创建spring_security模块

2、在spring_security引入相关依赖

3.代码结构说明:

4、创建spring security核心配置类

5、创建认证授权相关的工具类

(1)DefaultPasswordEncoder:密码处理的方法

(2)TokenManager:token操作的工具类

(3)TokenLogoutHandler:退出实现

(4)UnauthorizedEntryPoint:未授权统一处理

6、创建认证授权实体类

7、创建认证和授权的filter

(1)TokenLoginFilter:认证的filter


一、Spring Security介绍

1、框架介绍

Spring 是一个非常流行和成功的 Java 应用开发框架。Spring Security 基于 Spring 框架,提供了一套 Web 应用安全性的完整解决方案。一般来说,Web 应用的安全性包括用户认证Authentication)和用户授权(Authorization两个部分。

(1)用户认证指的是:验证某个用户是否为系统中的合法主体,也就是说用户能否访问该系统。用户认证一般要求用户提供用户名和密码。系统通过校验用户名和密码来完成认证过程。

(2)用户授权指的是验证某个用户是否有权限执行某个操作。在一个系统中,不同用户所具有的权限是不同的。比如对一个文件来说,有的用户只能进行读取,而有的用户可以进行修改。一般来说,系统会为不同的用户分配不同的角色,而每个角色则对应一系列的权限。

Spring Security其实就是用filter,多请求的路径进行过滤。

(1)如果是基于Session,那么Spring-security会对cookie里的sessionid进行解析,找到服务器存储的sesion信息,然后判断当前用户是否符合请求的要求。

(2)如果是token,则是解析出token,然后将当前请求加入到Spring-security管理的权限信息中去

2、认证与授权实现思路

如果系统的模块众多,每个模块都需要就行授权与认证,所以我们选择基于token的形式进行授权与认证,用户根据用户名密码认证成功,然后获取当前用户角色的一系列权限值,并以用户名为key,权限列表为value的形式存入redis缓存中,根据用户名相关信息生成token返回,浏览器将token记录到cookie中,每次调用api接口都默认将token携带到header请求头中,Spring-security解析header头获取token信息,解析token获取当前用户名,根据用户名就可以从redis中获取权限列表,这样Spring-security就能够判断当前请求是否有权限访问

二、整合Spring Security

1、在common下创建spring_security模块

2、在spring_security引入相关依赖

<properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>
    <dependencies>
    <dependency>
        <groupId>com.xingchen</groupId>
        <artifactId>commentUtils</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    </dependency>
    <!-- Spring Security依赖 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
    </dependency>

    <dependency>
        <groupId>io.jsonwebtoken</groupId>
        <artifactId>jjwt</artifactId>
    </dependency>
</dependencies>
 

3.代码结构说明:

4、创建spring security核心配置类

Spring Security的核心配置就是继承WebSecurityConfigurerAdapter并注解@EnableWebSecurity的配置。

这个配置指明了用户名密码的处理方式、请求路径的开合、登录登出控制等和安全相关的配置

  1. package com.xingchen.sercurity.config;
  2. import com.xingchen.sercurity.filter.TokenAuthenticationFilter;
  3. import com.xingchen.sercurity.filter.TokenLoginFilter;
  4. import com.xingchen.sercurity.security.DefaultPasswordEncoder;
  5. import com.xingchen.sercurity.security.TokenLogoutHandler;
  6. import com.xingchen.sercurity.security.TokenManager;
  7. import com.xingchen.sercurity.security.UnauthorizedEntryPoint;
  8. import org.springframework.beans.factory.annotation.Autowired;
  9. import org.springframework.context.annotation.Configuration;
  10. import org.springframework.data.redis.core.RedisTemplate;
  11. import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
  12. import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
  13. import org.springframework.security.config.annotation.web.builders.HttpSecurity;
  14. import org.springframework.security.config.annotation.web.builders.WebSecurity;
  15. import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
  16. import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
  17. import org.springframework.security.core.userdetails.UserDetailsService;
  18. /**
  19. * @author xing'chen
  20. */
  21. @Configuration
  22. @EnableWebSecurity
  23. @EnableGlobalMethodSecurity(prePostEnabled = true)
  24. public class TokenWebSecurityConfig extends WebSecurityConfigurerAdapter {
  25. private UserDetailsService userDetailsService;
  26. private TokenManager tokenManager;
  27. private DefaultPasswordEncoder defaultPasswordEncoder;
  28. private RedisTemplate redisTemplate;
  29. @Autowired
  30. public TokenWebSecurityConfig(UserDetailsService userDetailsService, DefaultPasswordEncoder defaultPasswordEncoder,
  31. TokenManager tokenManager, RedisTemplate redisTemplate) {
  32. this.userDetailsService = userDetailsService;
  33. this.defaultPasswordEncoder = defaultPasswordEncoder;
  34. this.tokenManager = tokenManager;
  35. this.redisTemplate = redisTemplate;
  36. }
  37. /**
  38. * 配置设置
  39. * @param http
  40. * @throws Exception
  41. */
  42. @Override
  43. protected void configure(HttpSecurity http) throws Exception {
  44. http.exceptionHandling()
  45. .authenticationEntryPoint(new UnauthorizedEntryPoint())
  46. .and().csrf().disable()
  47. .authorizeRequests()
  48. .anyRequest().authenticated()
  49. .and().logout().logoutUrl("/admin/acl/index/logout")
  50. .addLogoutHandler(new TokenLogoutHandler(tokenManager,redisTemplate)).and()
  51. .addFilter(new TokenLoginFilter(authenticationManager(), tokenManager, redisTemplate))
  52. .addFilter(new TokenAuthenticationFilter(authenticationManager(), tokenManager, redisTemplate)).httpBasic();
  53. }
  54. /**
  55. * 密码处理
  56. * @param auth
  57. * @throws Exception
  58. */
  59. @Override
  60. public void configure(AuthenticationManagerBuilder auth) throws Exception {
  61. auth.userDetailsService(userDetailsService).passwordEncoder(defaultPasswordEncoder);
  62. }
  63. /**
  64. * 配置哪些请求不拦截
  65. * @param web
  66. * @throws Exception
  67. */
  68. @Override
  69. public void configure(WebSecurity web) throws Exception {
  70. // web.ignoring().antMatchers("/api/**",
  71. // "/swagger-resources/**", "/webjars/**", "/v2/**", "/swagger-ui.html/**"
  72. // );
  73. web.ignoring().antMatchers("/*/**"
  74. );
  75. }
  76. }

5、创建认证授权相关的工具类

(1)DefaultPasswordEncoder:密码处理的方法

  1. package com.xingchen.sercurity.security;
  2. import com.xingchen.utils.MD5;
  3. import org.springframework.security.crypto.password.PasswordEncoder;
  4. import org.springframework.stereotype.Component;
  5. /**
  6. * @author xing'chen
  7. *
  8. * * t密码的处理方法类型
  9. */
  10. @Component
  11. public class DefaultPasswordEncoder implements PasswordEncoder {
  12. public DefaultPasswordEncoder() {
  13. this(-1);
  14. }
  15. /**
  16. * @param strength
  17. * the log rounds to use, between 4 and 31
  18. */
  19. public DefaultPasswordEncoder(int strength) {
  20. }
  21. @Override
  22. public String encode(CharSequence rawPassword) {
  23. return MD5.encrypt(rawPassword.toString());
  24. }
  25. @Override
  26. public boolean matches(CharSequence rawPassword, String encodedPassword) {
  27. return encodedPassword.equals(MD5.encrypt(rawPassword.toString()));
  28. }
  29. }

(2)TokenManager:token操作的工具类

  1. package com.xingchen.sercurity.security;
  2. import io.jsonwebtoken.CompressionCodecs;
  3. import io.jsonwebtoken.Jwts;
  4. import io.jsonwebtoken.SignatureAlgorithm;
  5. import org.springframework.stereotype.Component;
  6. import java.util.Date;
  7. /**
  8. * @author xing'chen
  9. * * token管理
  10. */
  11. @Component
  12. public class TokenManager {
  13. private long tokenExpiration = 24*60*60*1000;
  14. private String tokenSignKey = "123456";
  15. public String createToken(String username) {
  16. String token = Jwts.builder().setSubject(username)
  17. .setExpiration(new Date(System.currentTimeMillis() + tokenExpiration))
  18. .signWith(SignatureAlgorithm.HS512, tokenSignKey).compressWith(CompressionCodecs.GZIP).compact();
  19. return token;
  20. }
  21. public String getUserFromToken(String token) {
  22. String user = Jwts.parser().setSigningKey(tokenSignKey).parseClaimsJws(token).getBody().getSubject();
  23. return user;
  24. }
  25. public void removeToken(String token) {
  26. //jwttoken无需删除,客户端扔掉即可。
  27. }
  28. }

(3)TokenLogoutHandler:退出实现

  1. package com.xingchen.sercurity.security;
  2. import com.xingchen.utils.*;
  3. import org.springframework.data.redis.core.RedisTemplate;
  4. import org.springframework.security.core.Authentication;
  5. import org.springframework.security.web.authentication.logout.LogoutHandler;
  6. import javax.servlet.http.HttpServletRequest;
  7. import javax.servlet.http.HttpServletResponse;
  8. /**
  9. * @author xing'chen
  10. * * 登出业务逻辑类
  11. */
  12. public class TokenLogoutHandler implements LogoutHandler {
  13. private TokenManager tokenManager;
  14. private RedisTemplate redisTemplate;
  15. public TokenLogoutHandler(TokenManager tokenManager, RedisTemplate redisTemplate) {
  16. this.tokenManager = tokenManager;
  17. this.redisTemplate = redisTemplate;
  18. }
  19. @Override
  20. public void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {
  21. String token = request.getHeader("token");
  22. if (token != null) {
  23. tokenManager.removeToken(token);
  24. //清空当前用户缓存中的权限数据
  25. String userName = tokenManager.getUserFromToken(token);
  26. redisTemplate.delete(userName);
  27. }
  28. ResponseUtil.out(response, R.ok());
  29. }
  30. }

(4)UnauthorizedEntryPoint:未授权统一处理

  1. package com.xingchen.sercurity.security;
  2. import com.xingchen.utils.R;
  3. import com.xingchen.utils.ResponseUtil;
  4. import org.springframework.security.core.AuthenticationException;
  5. import org.springframework.security.web.AuthenticationEntryPoint;
  6. import javax.servlet.ServletException;
  7. import javax.servlet.http.HttpServletRequest;
  8. import javax.servlet.http.HttpServletResponse;
  9. import java.io.IOException;
  10. /**
  11. * @author xing'chen
  12. *
  13. * * 未授权的统一处理方式
  14. */
  15. public class UnauthorizedEntryPoint implements AuthenticationEntryPoint {
  16. @Override
  17. public void commence(HttpServletRequest request, HttpServletResponse response,
  18. AuthenticationException authException) throws IOException, ServletException {
  19. ResponseUtil.out(response, R.error());
  20. }
  21. }

6、创建认证授权实体类

(1)SecutityUser

  1. package com.xingchen.sercurity.entity;
  2. import lombok.Data;
  3. import lombok.extern.slf4j.Slf4j;
  4. import org.springframework.security.core.GrantedAuthority;
  5. import org.springframework.security.core.authority.SimpleGrantedAuthority;
  6. import org.springframework.security.core.userdetails.UserDetails;
  7. import org.springframework.util.StringUtils;
  8. import java.util.ArrayList;
  9. import java.util.Collection;
  10. import java.util.List;
  11. /**
  12. * @author xingchen
  13. * * 安全认证用户详情信息
  14. */
  15. @Data
  16. @Slf4j
  17. public class SecurityUser implements UserDetails {
  18. //当前登录用户
  19. private transient User currentUserInfo;
  20. //当前权限
  21. private List<String> permissionValueList;
  22. public SecurityUser() {
  23. }
  24. public SecurityUser(User user) {
  25. if (user != null) {
  26. this.currentUserInfo = user;
  27. }
  28. }
  29. @Override
  30. public Collection<? extends GrantedAuthority> getAuthorities() {
  31. Collection<GrantedAuthority> authorities = new ArrayList<>();
  32. for(String permissionValue : permissionValueList) {
  33. if(StringUtils.isEmpty(permissionValue)) continue;
  34. SimpleGrantedAuthority authority = new SimpleGrantedAuthority(permissionValue);
  35. authorities.add(authority);
  36. }
  37. return authorities;
  38. }
  39. @Override
  40. public String getPassword() {
  41. return currentUserInfo.getPassword();
  42. }
  43. @Override
  44. public String getUsername() {
  45. return currentUserInfo.getUsername();
  46. }
  47. @Override
  48. public boolean isAccountNonExpired() {
  49. return true;
  50. }
  51. @Override
  52. public boolean isAccountNonLocked() {
  53. return true;
  54. }
  55. @Override
  56. public boolean isCredentialsNonExpired() {
  57. return true;
  58. }
  59. @Override
  60. public boolean isEnabled() {
  61. return true;
  62. }
  63. }

(2)User

  1. package com.xingchen.sercurity.entity;
  2. import io.swagger.annotations.ApiModel;
  3. import io.swagger.annotations.ApiModelProperty;
  4. import lombok.Data;
  5. import java.io.Serializable;
  6. /**
  7. * @author xing'chen
  8. *
  9. * * 用户实体类
  10. */
  11. @Data
  12. @ApiModel(description = "用户实体类")
  13. public class User implements Serializable {
  14. private static final long serialVersionUID = 1L;
  15. @ApiModelProperty(value = "微信openid")
  16. private String username;
  17. @ApiModelProperty(value = "密码")
  18. private String password;
  19. @ApiModelProperty(value = "昵称")
  20. private String nickName;
  21. @ApiModelProperty(value = "用户头像")
  22. private String salt;
  23. @ApiModelProperty(value = "用户签名")
  24. private String token;
  25. }

7、创建认证和授权的filter

(1)TokenLoginFilter:认证的filter

  1. package com.xingchen.sercurity.filter;
  2. import com.fasterxml.jackson.databind.ObjectMapper;
  3. import com.xingchen.sercurity.entity.SecurityUser;
  4. import com.xingchen.sercurity.entity.User;
  5. import com.xingchen.sercurity.security.TokenManager;
  6. import com.xingchen.utils.R;
  7. import com.xingchen.utils.ResponseUtil;
  8. import org.springframework.data.redis.core.RedisTemplate;
  9. import org.springframework.security.authentication.AuthenticationManager;
  10. import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
  11. import org.springframework.security.core.Authentication;
  12. import org.springframework.security.core.AuthenticationException;
  13. import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
  14. import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
  15. import javax.servlet.FilterChain;
  16. import javax.servlet.ServletException;
  17. import javax.servlet.http.HttpServletRequest;
  18. import javax.servlet.http.HttpServletResponse;
  19. import java.io.IOException;
  20. import java.util.ArrayList;
  21. /**
  22. * @author xingchen
  23. * * 登录过滤器,继承UsernamePasswordAuthenticationFilter,对用户名密码进行登录校验
  24. */
  25. public class TokenLoginFilter extends UsernamePasswordAuthenticationFilter {
  26. private AuthenticationManager authenticationManager;
  27. private TokenManager tokenManager;
  28. private RedisTemplate redisTemplate;
  29. public TokenLoginFilter(AuthenticationManager authenticationManager, TokenManager tokenManager, RedisTemplate redisTemplate) {
  30. this.authenticationManager = authenticationManager;
  31. this.tokenManager = tokenManager;
  32. this.redisTemplate = redisTemplate;
  33. this.setPostOnly(false);
  34. this.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("/admin/acl/login","POST"));
  35. }
  36. @Override
  37. public Authentication attemptAuthentication(HttpServletRequest req, HttpServletResponse res)
  38. throws AuthenticationException {
  39. try {
  40. User user = new ObjectMapper().readValue(req.getInputStream(), User.class);
  41. return authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(user.getUsername(), user.getPassword(), new ArrayList<>()));
  42. } catch (IOException e) {
  43. throw new RuntimeException(e);
  44. }
  45. }
  46. /**
  47. * 登录成功
  48. * @param req
  49. * @param res
  50. * @param chain
  51. * @param auth
  52. * @throws IOException
  53. * @throws ServletException
  54. */
  55. @Override
  56. protected void successfulAuthentication(HttpServletRequest req, HttpServletResponse res, FilterChain chain,
  57. Authentication auth) throws IOException, ServletException {
  58. SecurityUser user = (SecurityUser) auth.getPrincipal();
  59. String token = tokenManager.createToken(user.getCurrentUserInfo().getUsername());
  60. redisTemplate.opsForValue().set(user.getCurrentUserInfo().getUsername(), user.getPermissionValueList());
  61. ResponseUtil.out(res, R.ok().data("token", token));
  62. }
  63. /**
  64. * 登录失败
  65. * @param request
  66. * @param response
  67. * @param e
  68. * @throws IOException
  69. * @throws ServletException
  70. */
  71. @Override
  72. protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response,
  73. AuthenticationException e) throws IOException, ServletException {
  74. ResponseUtil.out(response, R.error());
  75. }
  76. }

(2)TokenAuthenticationFilter:

授权filter

  1. package com.xingchen.sercurity.filter;
  2. import com.xingchen.sercurity.security.TokenManager;
  3. import com.xingchen.utils.R;
  4. import com.xingchen.utils.ResponseUtil;
  5. import org.springframework.data.redis.core.RedisTemplate;
  6. import org.springframework.security.authentication.AuthenticationManager;
  7. import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
  8. import org.springframework.security.core.GrantedAuthority;
  9. import org.springframework.security.core.authority.SimpleGrantedAuthority;
  10. import org.springframework.security.core.context.SecurityContextHolder;
  11. import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
  12. import org.springframework.util.StringUtils;
  13. import javax.servlet.FilterChain;
  14. import javax.servlet.ServletException;
  15. import javax.servlet.http.HttpServletRequest;
  16. import javax.servlet.http.HttpServletResponse;
  17. import java.io.IOException;
  18. import java.util.ArrayList;
  19. import java.util.Collection;
  20. import java.util.List;
  21. /**
  22. * @author xingchen
  23. * * 访问过滤器
  24. */
  25. public class TokenAuthenticationFilter extends BasicAuthenticationFilter {
  26. private TokenManager tokenManager;
  27. private RedisTemplate redisTemplate;
  28. public TokenAuthenticationFilter(AuthenticationManager authManager, TokenManager tokenManager,RedisTemplate redisTemplate) {
  29. super(authManager);
  30. this.tokenManager = tokenManager;
  31. this.redisTemplate = redisTemplate;
  32. }
  33. @Override
  34. protected void doFilterInternal(HttpServletRequest req, HttpServletResponse res, FilterChain chain)
  35. throws IOException, ServletException {
  36. logger.info("================="+req.getRequestURI());
  37. if(req.getRequestURI().indexOf("admin") == -1) {
  38. chain.doFilter(req, res);
  39. return;
  40. }
  41. UsernamePasswordAuthenticationToken authentication = null;
  42. try {
  43. authentication = getAuthentication(req);
  44. } catch (Exception e) {
  45. ResponseUtil.out(res, R.error());
  46. }
  47. if (authentication != null) {
  48. SecurityContextHolder.getContext().setAuthentication(authentication);
  49. } else {
  50. ResponseUtil.out(res, R.error());
  51. }
  52. chain.doFilter(req, res);
  53. }
  54. private UsernamePasswordAuthenticationToken getAuthentication(HttpServletRequest request) {
  55. // token置于header里
  56. String token = request.getHeader("token");
  57. if (token != null && !"".equals(token.trim())) {
  58. String userName = tokenManager.getUserFromToken(token);
  59. List<String> permissionValueList = (List<String>) redisTemplate.opsForValue().get(userName);
  60. Collection<GrantedAuthority> authorities = new ArrayList<>();
  61. for(String permissionValue : permissionValueList) {
  62. if(StringUtils.isEmpty(permissionValue)) {
  63. continue;
  64. }
  65. SimpleGrantedAuthority authority = new SimpleGrantedAuthority(permissionValue);
  66. authorities.add(authority);
  67. }
  68. if (!StringUtils.isEmpty(userName)) {
  69. return new UsernamePasswordAuthenticationToken(userName, token, authorities);
  70. }
  71. return null;
  72. }
  73. return null;
  74. }
  75. }

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

闽ICP备14008679号