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<String,Object> 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<? extends GrantedAuthority> authorities, Map<String,Object> 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<String,Object> 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<String,Object> 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;

/**
 * <p> 自定义用户密码校验过滤器 </p>
 *
 * @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<String,Object> 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<String,Object> 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;

/**
 *  <p> 自定义认证处理 </p>
 *
 * @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<String,Object> 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"}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值