Spring Security 后端接受多个参数

有时候,我们用到Spring Security验证框架的时候需要用到多个参数,因为默认提供了2个参数username和password,加入我们需要curLoginType这个参数怎么设置

1.重写UsernamePasswordAuthenticationToken这个类,由于这个类已经有spring封装,我们把源代码改一下,重新命名为MyAuthenticationToken,代码如下:

package com.zhengqing.config.security.filter;

import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;

import java.util.Collection;
import java.util.Map;

public class MyAuthenticationToken extends AbstractAuthenticationToken {
    private static final long serialVersionUID = 420L;
    private final Object principal;
    private Object credentials;

    /**
     * 参数map
     */
    private Map map;

    public MyAuthenticationToken(Object principal, Object credentials) {
        super((Collection)null);
        this.principal = principal;
        this.credentials = credentials;
        this.setAuthenticated(false);
    }

    public MyAuthenticationToken(Object principal, Object credentials, Collection authorities, Map map){
        super(authorities);
        this.principal = principal;
        this.credentials = credentials;
        super.setAuthenticated(true);
        this.map=map;
    }

    public Object getCredentials() {
        return this.credentials;
    }

    public Object getPrincipal() {
        return this.principal;
    }

    public Map getParam(){
        return map;
    }

    public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException {
        if (isAuthenticated) {
            throw new IllegalArgumentException("Cannot set this token to trusted - use constructor which takes a GrantedAuthority list instead");
        } else {
            super.setAuthenticated(false);
        }
    }

    public void eraseCredentials() {
        super.eraseCredentials();
        this.credentials = null;
    }
}

注意:我改了代码加了一个属性Map,成为参数Map

  /**
     * 参数map
     */
    private Map map;

2.将自定义用户名密码过滤器中的 UsernamePasswordAuthenticationToken替换成自己的MyAuthenticationToken 即可:

package com.zhengqing.config.security.filter;

import com.alibaba.fastjson.JSONObject;
import com.zhengqing.config.Constants;
import com.zhengqing.config.security.login.CusAuthenticationManager;
import com.zhengqing.utils.MultiReadHttpServletRequest;
import com.zhengqing.config.security.login.AdminAuthenticationFailureHandler;
import com.zhengqing.config.security.login.AdminAuthenticationSuccessHandler;
import com.zhengqing.modules.system.entity.User;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.Map;

/**
 * 

自定义用户密码校验过滤器

* * @author : zhengqing * @description : * @date : 2019/10/12 15:32 */ @Slf4j @Component public class AdminAuthenticationProcessingFilter extends AbstractAuthenticationProcessingFilter { /** * @param authenticationManager: 认证管理器 * @param adminAuthenticationSuccessHandler: 认证成功处理 * @param adminAuthenticationFailureHandler: 认证失败处理 */ public AdminAuthenticationProcessingFilter(CusAuthenticationManager authenticationManager, AdminAuthenticationSuccessHandler adminAuthenticationSuccessHandler, AdminAuthenticationFailureHandler adminAuthenticationFailureHandler) { super(new AntPathRequestMatcher("/login", "POST")); this.setAuthenticationManager(authenticationManager); this.setAuthenticationSuccessHandler(adminAuthenticationSuccessHandler); this.setAuthenticationFailureHandler(adminAuthenticationFailureHandler); } @Override public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException { if (request.getContentType() == null || !request.getContentType().contains(Constants.REQUEST_HEADERS_CONTENT_TYPE)) { throw new AuthenticationServiceException("请求头类型不支持: " + request.getContentType()); } MyAuthenticationToken authRequest; try { MultiReadHttpServletRequest wrappedRequest = new MultiReadHttpServletRequest(request); // 将前端传递的数据转换成jsonBean数据格式 User user = JSONObject.parseObject(wrappedRequest.getBodyJsonStrByJson(wrappedRequest), User.class); String curLoginType=user.getCurLoginType(); Map map=new HashMap<>(); map.put("curLoginType",curLoginType); authRequest = new MyAuthenticationToken(user.getUsername(), user.getPassword(), null,map); authRequest.setDetails(authenticationDetailsSource.buildDetails(wrappedRequest)); } catch (Exception e) { throw new AuthenticationServiceException(e.getMessage()); } Authentication ac =this.getAuthenticationManager().authenticate(authRequest); return ac; } }

注意:

            // 将前端传递的数据转换成jsonBean数据格式
            User user = JSONObject.parseObject(wrappedRequest.getBodyJsonStrByJson(wrappedRequest), User.class);

这个user对象是用户自定义的,我这里加了一个参数为curLoginType,前端curLoginType会自动封装到这个user里面,

后面这段代码

           String curLoginType=user.getCurLoginType();
            Map map=new HashMap<>();
            map.put("curLoginType",curLoginType);
            authRequest = new MyAuthenticationToken(user.getUsername(), user.getPassword(), null,map);

就将参数封装到map中去了,这个map就在我的MyAuthenticationToken 这个类的参数map中

3.取值

package com.zhengqing.config.security.login;

import com.alibaba.fastjson.JSONObject;
import com.zhengqing.config.Constants;
import com.zhengqing.config.MyProperties;
import com.zhengqing.config.security.dto.SecurityUser;
import com.zhengqing.config.security.filter.MyAuthenticationToken;
import com.zhengqing.config.security.service.impl.UserDetailsServiceImpl;
import com.zhengqing.modules.system.entity.User;
import com.zhengqing.modules.system.mapper.UserMapper;
import com.zhengqing.utils.ApplicationContextUtil;
import com.zhengqing.utils.MultiReadHttpServletRequest;
import com.zhengqing.utils.PasswordUtils;
import com.zhengqing.utils.RedisUtils;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.MapUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 *  

自定义认证处理

* * @description : * @author : zhengqing * @date : 2019/10/12 14:49 */ @Component @Slf4j public class AdminAuthenticationProvider implements AuthenticationProvider { @Autowired UserDetailsServiceImpl userDetailsService; @Autowired private UserMapper userMapper; @Autowired MyProperties MyProperties; @Autowired RedisUtils redisUtils; @Override public Authentication authenticate(Authentication authentication) throws AuthenticationException { MyAuthenticationToken authRequest=(MyAuthenticationToken)authentication; String curLoginType= MapUtils.getString(authRequest.getParam(),"curLoginType","-1"); // 获取前端表单中输入后返回的用户名、密码 String userName = (String) authentication.getPrincipal(); String password = (String) authentication.getCredentials(); SecurityUser userInfo = (SecurityUser) userDetailsService.loadUserByUsername(userName); boolean isValid = PasswordUtils.isValidPassword(password, userInfo.getPassword(), userInfo.getCurrentUserInfo().getSalt()); // 验证密码 if (!isValid) { throw new BadCredentialsException("密码错误!"); } // 前后端分离情况下 处理逻辑... // 更新登录令牌 String token = PasswordUtils.encodePassword(String.valueOf(System.currentTimeMillis()), Constants.SALT); //将token更新到数据库中,每次登陆进去要将redis中的token清空,实现挤兑登录 User user = userMapper.selectById(userInfo.getCurrentUserInfo().getId()); String oldToken=user.getToken(); user.setToken(token); userMapper.updateById(user); // 当前用户所拥有角色代码 String roleCodes = userInfo.getRoleCodes(); // 生成jwt访问令牌 /*String jwt = Jwts.builder() // 用户角色 .claim(Constants.ROLE_LOGIN, roleCodes) // 主题 - 存用户名 .setSubject(authentication.getName()) // 过期时间 .setExpiration(new Date(System.currentTimeMillis() + 30 * 60 * MyProperties.getAuth().getTokenExpireTime())) // 加密算法和密钥 .signWith(SignatureAlgorithm.HS512, Constants.SALT) .compact();*/ Map redisMap=new HashMap<>(); //将用户信息存入redis redisMap.put(Constants.REDIS_KEY,userInfo); log.info("jwt有效时间为: "+MyProperties.getAuth().getTokenExpireTime()); //token作为键存入redis redisUtils.redisTimeSet(token,MyProperties.getAuth().getTokenExpireTime(),redisMap); //登录成功后将原来的token清空 redisUtils.redisDel(oldToken); userInfo.getCurrentUserInfo().setToken(token); MyAuthenticationToken result = new MyAuthenticationToken(userInfo, userInfo.getAuthorities()); //return new UsernamePasswordAuthenticationToken(userInfo, password, userInfo.getAuthorities()); return result; } @Override public boolean supports(Class aClass) { return true; } }

注意

       MyAuthenticationToken authRequest=(MyAuthenticationToken)authentication;
       String curLoginType= MapUtils.getString(authRequest.getParam(),"curLoginType","-1");

通过强制转换就可以得到我自定义的那个类MyAuthenticationToken,就可以找到这个参数map了,很巧妙的解决了多个参数的传递问题

注意,本例有很多与本话题无关的代码,只需要细读关键代码即可!

附上前端postman传参:

{"username":"admin2","password":"123456","curLoginType":"1"}

你可能感兴趣的:(传参,Spring,Security传参问题,Spring,Security多参数传递)