• springsecurity 配置


    1、框架介绍

    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就能够判断当前请求是否有权限访问

    3. 配置与使用

    1.依赖引入

        <dependencies>
            <dependency>
                <groupId>com.atguigu</groupId>
                <artifactId>common-util</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>
    pom

    2. 各类功能介绍

     1. security

     1 import com.atguigu.commonutils.MD5;
     2 import org.springframework.security.crypto.password.PasswordEncoder;
     3 import org.springframework.stereotype.Component;
     4 
     5 /**
     6  * <p>
     7  * t密码的处理方法类型
     8  * </p>
     9  *
    10  */
    11 @Component
    12 public class DefaultPasswordEncoder implements PasswordEncoder {
    13 
    14     public DefaultPasswordEncoder() {
    15         this(-1);
    16     }
    17 
    18     /**
    19      * @param strength
    20      *            the log rounds to use, between 4 and 31
    21      */
    22     public DefaultPasswordEncoder(int strength) {
    23 
    24     }
    25 
    26     public String encode(CharSequence rawPassword) {
    27         return MD5.encrypt(rawPassword.toString());
    28     }
    29 
    30     public boolean matches(CharSequence rawPassword, String encodedPassword) {
    31         return encodedPassword.equals(MD5.encrypt(rawPassword.toString()));
    32     }
    33 }
    DefaultPasswordEncoder
     1 import com.atguigu.commonutils.R;
     2 import com.atguigu.commonutils.ResponseUtil;
     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 
     7 import javax.servlet.http.HttpServletRequest;
     8 import javax.servlet.http.HttpServletResponse;
     9 
    10 /**
    11  * <p>
    12  * 登出业务逻辑类
    13  * </p>
    14  *
    15  */
    16 public class TokenLogoutHandler implements LogoutHandler {
    17 
    18     private TokenManager tokenManager;
    19     private RedisTemplate redisTemplate;
    20 
    21     public TokenLogoutHandler(TokenManager tokenManager, RedisTemplate redisTemplate) {
    22         this.tokenManager = tokenManager;
    23         this.redisTemplate = redisTemplate;
    24     }
    25 
    26     @Override
    27     public void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {
    28         String token = request.getHeader("token");
    29         if (token != null) {
    30             tokenManager.removeToken(token); // 该行其实没有处理
    31 
    32             //清空当前用户缓存中的权限数据
    33             String userName = tokenManager.getUserFromToken(token);
    34             redisTemplate.delete(userName);
    35         }
    36 
    37         ResponseUtil.out(response, R.ok());
    38     }
    39 
    40 }
    TokenLogoutHandler
     1 import io.jsonwebtoken.CompressionCodecs;
     2 import io.jsonwebtoken.Jwts;
     3 import io.jsonwebtoken.SignatureAlgorithm;
     4 import org.springframework.stereotype.Component;
     5 
     6 import java.util.Date;
     7 
     8 /**
     9  * <p>
    10  * token管理
    11  * </p>
    12  *
    13  */
    14 @Component
    15 public class TokenManager {
    16 
    17     private long tokenExpiration = 24*60*60*1000;
    18     private String tokenSignKey = "123456";
    19 
    20     public String createToken(String username) {
    21         String token = Jwts.builder().setSubject(username)
    22                 .setExpiration(new Date(System.currentTimeMillis() + tokenExpiration))
    23                 .signWith(SignatureAlgorithm.HS512, tokenSignKey)
    24                 .compressWith(CompressionCodecs.GZIP)
    25                 .compact();
    26         return token;
    27     }
    28 
    29     public String getUserFromToken(String token) {
    30         String user = Jwts.parser().setSigningKey(tokenSignKey).parseClaimsJws(token).getBody().getSubject();
    31         return user;
    32     }
    33 
    34     public void removeToken(String token) {
    35         //jwttoken无需删除,客户端扔掉即可。
    36     }
    37 
    38 }
    TokenManager
     1 import com.atguigu.commonutils.R;
     2 import com.atguigu.commonutils.ResponseUtil;
     3 import org.springframework.security.core.AuthenticationException;
     4 import org.springframework.security.web.AuthenticationEntryPoint;
     5 
     6 import javax.servlet.ServletException;
     7 import javax.servlet.http.HttpServletRequest;
     8 import javax.servlet.http.HttpServletResponse;
     9 import java.io.IOException;
    10 
    11 /**
    12  * <p>
    13  * 未授权的统一处理方式
    14  * </p>
    15  *
    16  */
    17 public class UnauthorizedEntryPoint implements AuthenticationEntryPoint {
    18 
    19     @Override
    20     public void commence(HttpServletRequest request, HttpServletResponse response,
    21                          AuthenticationException authException) throws IOException, ServletException {
    22 
    23         ResponseUtil.out(response, R.error());
    24     }
    25 }
    UnauthorizedEntryPoint

    2.filter

     1 import com.atguigu.commonutils.R;
     2 import com.atguigu.commonutils.ResponseUtil;
     3 import com.atguigu.serurity.security.TokenManager;
     4 import org.springframework.data.redis.core.RedisTemplate;
     5 import org.springframework.security.authentication.AuthenticationManager;
     6 import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
     7 import org.springframework.security.core.GrantedAuthority;
     8 import org.springframework.security.core.authority.SimpleGrantedAuthority;
     9 import org.springframework.security.core.context.SecurityContextHolder;
    10 import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
    11 import org.springframework.util.StringUtils;
    12 
    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 /**
    23  * <p>
    24  * 访问过滤器
    25  * </p>
    26  *
    27  */
    28 public class TokenAuthenticationFilter extends BasicAuthenticationFilter {
    29     private TokenManager tokenManager;
    30     private RedisTemplate redisTemplate;
    31 
    32     public TokenAuthenticationFilter(AuthenticationManager authManager, TokenManager tokenManager,RedisTemplate redisTemplate) {
    33         super(authManager);
    34         this.tokenManager = tokenManager;
    35         this.redisTemplate = redisTemplate;
    36     }
    37 
    38     @Override
    39     protected void doFilterInternal(HttpServletRequest req, HttpServletResponse res, FilterChain chain)
    40             throws IOException, ServletException {
    41         // System.out.println("=================<"+req.getRequestURI());
    42         // System.out.println("===============token:" + req.getHeader("token"));
    43         if(req.getRequestURI().indexOf("admin") == -1) {
    44             chain.doFilter(req, res);
    45             return;
    46         }
    47 
    48         UsernamePasswordAuthenticationToken authentication = null;
    49         try {
    50             authentication = getAuthentication(req);
    51         } catch (Exception e) {
    52             ResponseUtil.out(res, R.error());
    53         }
    54 
    55         if (authentication != null) {
    56             System.out.println(authentication.getPrincipal());
    57             SecurityContextHolder.getContext().setAuthentication(authentication);
    58         } else {
    59             ResponseUtil.out(res, R.error());
    60         }
    61         chain.doFilter(req, res);
    62     }
    63 
    64     private UsernamePasswordAuthenticationToken getAuthentication(HttpServletRequest request) {
    65         // token置于header里
    66         String token = request.getHeader("token");
    67         // System.out.println("token=======>" + token);
    68         // token不为空或空字符串
    69         if (token != null && !"".equals(token.trim())) {
    70             String userName = tokenManager.getUserFromToken(token);
    71 
    72             List<String> permissionValueList = (List<String>) redisTemplate.opsForValue().get(userName);
    73             Collection<GrantedAuthority> authorities = new ArrayList<>();
    74             for(String permissionValue : permissionValueList) {
    75                 if(StringUtils.isEmpty(permissionValue)) continue;
    76                 SimpleGrantedAuthority authority = new SimpleGrantedAuthority(permissionValue);
    77                 authorities.add(authority);
    78             }
    79 
    80 
    81             if (!StringUtils.isEmpty(userName)) {
    82 
    83                 return new UsernamePasswordAuthenticationToken(userName, token, authorities);
    84             }
    85             return null;
    86         }
    87         return null;
    88     }
    89 }
    TokenAuthenticationFilter
     1 import com.atguigu.commonutils.R;
     2 import com.atguigu.commonutils.ResponseUtil;
     3 import com.atguigu.serurity.entity.SecurityUser;
     4 import com.atguigu.serurity.entity.User;
     5 import com.atguigu.serurity.security.TokenManager;
     6 import com.fasterxml.jackson.databind.ObjectMapper;
     7 import org.springframework.data.redis.core.RedisTemplate;
     8 import org.springframework.security.authentication.AuthenticationManager;
     9 import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
    10 import org.springframework.security.core.Authentication;
    11 import org.springframework.security.core.AuthenticationException;
    12 import org.springframework.security.core.context.SecurityContextHolder;
    13 import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
    14 import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
    15 
    16 import javax.servlet.FilterChain;
    17 import javax.servlet.ServletException;
    18 import javax.servlet.http.Cookie;
    19 import javax.servlet.http.HttpServletRequest;
    20 import javax.servlet.http.HttpServletResponse;
    21 import java.io.IOException;
    22 import java.util.ArrayList;
    23 
    24 /**
    25  * <p>
    26  * 登录过滤器,继承UsernamePasswordAuthenticationFilter,对用户名密码进行登录校验
    27  * </p>
    28  *
    29  */
    30 public class TokenLoginFilter extends UsernamePasswordAuthenticationFilter {
    31 
    32     private AuthenticationManager authenticationManager;
    33     private TokenManager tokenManager;
    34     private RedisTemplate redisTemplate;
    35 
    36     public TokenLoginFilter(AuthenticationManager authenticationManager, TokenManager tokenManager, RedisTemplate redisTemplate) {
    37         this.authenticationManager = authenticationManager;
    38         this.tokenManager = tokenManager;
    39         this.redisTemplate = redisTemplate;
    40         this.setPostOnly(false);
    41         AntPathRequestMatcher requestMatcher = new AntPathRequestMatcher("/admin/acl/login", "POST");
    42         System.out.println(requestMatcher);
    43         this.setRequiresAuthenticationRequestMatcher(requestMatcher);
    44 
    45     }
    46 
    47     @Override
    48     public Authentication attemptAuthentication(HttpServletRequest req, HttpServletResponse res)
    49             throws AuthenticationException {
    50         try {
    51             User user = new ObjectMapper().readValue(req.getInputStream(), User.class);
    52             System.out.println(user);
    53             UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(user.getUsername(), user.getPassword(), new ArrayList<>());
    54             return authenticationManager.authenticate(usernamePasswordAuthenticationToken);
    55         } catch (IOException e) {
    56             throw new RuntimeException(e);
    57         }
    58 
    59     }
    60 
    61     /**
    62      * 登录成功
    63      * @param req
    64      * @param res
    65      * @param chain
    66      * @param auth
    67      * @throws IOException
    68      * @throws ServletException
    69      */
    70     @Override
    71     protected void successfulAuthentication(HttpServletRequest req, HttpServletResponse res, FilterChain chain,
    72                                             Authentication auth) throws IOException, ServletException {
    73 
    74         SecurityUser user = (SecurityUser) auth.getPrincipal();
    75         String token = tokenManager.createToken(user.getCurrentUserInfo().getUsername());
    76         redisTemplate.opsForValue().set(user.getCurrentUserInfo().getUsername(), user.getPermissionValueList());
    77         res.setHeader("token",token);
    78         // System.out.println("token:" + token);
    79         ResponseUtil.out(res, R.ok().data("token", token));
    80     }
    81 
    82     /**
    83      * 登录失败
    84      * @param request
    85      * @param response
    86      * @param e
    87      * @throws IOException
    88      * @throws ServletException
    89      */
    90     @Override
    91     protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response,
    92                                               AuthenticationException e) throws IOException, ServletException {
    93         ResponseUtil.out(response, R.error());
    94     }
    95 }
    TokenLoginFilter

    3. entity

     1 import lombok.Data;
     2 import lombok.extern.slf4j.Slf4j;
     3 import org.springframework.security.core.GrantedAuthority;
     4 import org.springframework.security.core.authority.SimpleGrantedAuthority;
     5 import org.springframework.security.core.userdetails.UserDetails;
     6 import org.springframework.util.StringUtils;
     7 
     8 import java.util.ArrayList;
     9 import java.util.Collection;
    10 import java.util.List;
    11 
    12 /**
    13  * <p>
    14  * 安全认证用户详情信息
    15  * </p>
    16  *
    17  */
    18 @Data
    19 @Slf4j
    20 public class SecurityUser implements UserDetails {
    21 
    22     //当前登录用户 transient不被序列化
    23     private transient User currentUserInfo;
    24 
    25     //当前权限
    26     private List<String> permissionValueList;
    27 
    28     public SecurityUser() {
    29     }
    30 
    31     public SecurityUser(User user) {
    32         if (user != null) {
    33             this.currentUserInfo = user;
    34         }
    35     }
    36 
    37     @Override
    38     public Collection<? extends GrantedAuthority> getAuthorities() {
    39         Collection<GrantedAuthority> authorities = new ArrayList<>();
    40         for(String permissionValue : permissionValueList) {
    41             if(StringUtils.isEmpty(permissionValue)) continue;
    42             SimpleGrantedAuthority authority = new SimpleGrantedAuthority(permissionValue);
    43             authorities.add(authority);
    44         }
    45 
    46         return authorities;
    47     }
    48 
    49     @Override
    50     public String getPassword() {
    51         return currentUserInfo.getPassword();
    52     }
    53 
    54     @Override
    55     public String getUsername() {
    56         return currentUserInfo.getUsername();
    57     }
    58 
    59     @Override
    60     public boolean isAccountNonExpired() {
    61         return true;
    62     }
    63 
    64     @Override
    65     public boolean isAccountNonLocked() {
    66         return true;
    67     }
    68 
    69     @Override
    70     public boolean isCredentialsNonExpired() {
    71         return true;
    72     }
    73 
    74     @Override
    75     public boolean isEnabled() {
    76         return true;
    77     }
    78 }
    SecurityUser
     1 import io.swagger.annotations.ApiModel;
     2 import io.swagger.annotations.ApiModelProperty;
     3 import lombok.Data;
     4 
     5 import java.io.Serializable;
     6 
     7 /**
     8  * <p>
     9  * 用户实体类
    10  * </p>
    11  *
    12  */
    13 @Data
    14 @ApiModel(description = "用户实体类")
    15 public class User implements Serializable {
    16 
    17     private static final long serialVersionUID = 1L;
    18 
    19     @ApiModelProperty(value = "微信openid")
    20     private String username;
    21 
    22     @ApiModelProperty(value = "密码")
    23     private String password;
    24 
    25     @ApiModelProperty(value = "昵称")
    26     private String nickName;
    27 
    28     @ApiModelProperty(value = "用户头像")
    29     private String salt;
    30 
    31     @ApiModelProperty(value = "用户签名")
    32     private String token;
    33 
    34 }
    User

    4. config

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

    5. 需要查询数据库所获得的用户信息接口UserDetailsService 的实现类

     1 import com.atguigu.aclservice.entity.User;
     2 import com.atguigu.aclservice.service.PermissionService;
     3 import com.atguigu.aclservice.service.UserService;
     4 import com.atguigu.serurity.entity.SecurityUser;
     5 import org.springframework.beans.BeanUtils;
     6 import org.springframework.beans.factory.annotation.Autowired;
     7 import org.springframework.security.core.userdetails.UserDetails;
     8 import org.springframework.security.core.userdetails.UserDetailsService;
     9 import org.springframework.security.core.userdetails.UsernameNotFoundException;
    10 import org.springframework.stereotype.Service;
    11 
    12 import java.util.List;
    13 
    14 
    15 /**
    16  * <p>
    17  * 自定义userDetailsService - 认证用户详情
    18  * </p>
    19  *
    20  */
    21 @Service("userDetailsService")
    22 public class UserDetailsServiceImpl implements UserDetailsService {
    23 
    24     @Autowired
    25     private UserService userService;
    26 
    27     @Autowired
    28     private PermissionService permissionService;
    29 
    30     /***
    31      * 根据账号获取用户信息
    32      * @param username:
    33      * @return: org.springframework.security.core.userdetails.UserDetails
    34      */
    35     @Override
    36     public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
    37         // 从数据库中取出用户信息
    38         User user = userService.selectByUsername(username);
    39         System.out.println("user:" + user);
    40 
    41         // 判断用户是否存在
    42         if (null == user){
    43             //throw new UsernameNotFoundException("用户名不存在!");
    44         }
    45         // 返回UserDetails实现类
    46         com.atguigu.serurity.entity.User curUser = new com.atguigu.serurity.entity.User();
    47         BeanUtils.copyProperties(user,curUser);
    48 
    49         List<String> authorities = permissionService.selectPermissionValueByUserId(user.getId());
    50         System.out.println("下面:" + authorities.get(0));
    51         SecurityUser securityUser = new SecurityUser(curUser);
    52         securityUser.setPermissionValueList(authorities);
    53         return securityUser;
    54     }
    55 
    56 }
    UserDetailsServiceImpl
    作者:zhangshuai
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须在文章页面给出原文连接,否则保留追究法律责任的权利。
  • 相关阅读:
    configuring express for ejs
    if else in EJS
    nodegroupchat exercise
    heap&stack 区别
    如何构建积木式Web应用(引自微软CSDN )
    Configuring IIS: Mapping .* to the aspnet_isapi.dll
    递归遍历XML生成树
    数据库应用:无法更新到数据库
    C#中HashTable的用法
    如何使用Eclipse编译C,C++,JAVA程序
  • 原文地址:https://www.cnblogs.com/zhangshaui/p/15062530.html
Copyright © 2020-2023  润新知