美文网首页
Caused by: org.springframework.s

Caused by: org.springframework.s

作者: 墨色尘埃 | 来源:发表于2018-11-01 14:33 被阅读14次

    使用spring security登陆的时候一直报这个错Caused by: org.springframework.security.authentication.BadCredentialsException: Bad credentials
    这是因为表里的密码是StandardPasswordEncoder()加密方式,而application.yml根据dev、prod环境来使用一种加密方式。如果测试环境也是使用
    StandardPasswordEncoder()加密方式,而后另一位同事不知情的情况下改为NoOpPasswordEncoder.getInstance()加密方式就会导致request.login(userId, pwd);登陆失败

        //密码加密对象
        @Bean
        public PasswordEncoder passwordEncoder() {
            if (envActive.equals("prod")) {  //生产环境下加密方式
                return new StandardPasswordEncoder();
            } else {
    //            return NoOpPasswordEncoder.getInstance();  //测试环境加密方式
                return new StandardPasswordEncoder();
            }
        }
    

    SecurityController

    package com.cicdi.servertemplate.modules.sys.controller;
    
    
    import com.cicdi.servertemplate.modules.sys.model.LoginInfo;
    import com.cicdi.servertemplate.common.config.security.ISpringSecurityService;
    import com.cicdi.servertemplate.common.config.security.SpringCacheModuleSecurity;
    import com.cicdi.servertemplate.common.config.security.SpringCacheRoleHierarchy;
    import com.cicdi.servertemplate.common.exception.BusinessException;
    import com.cicdi.servertemplate.common.model.ResponseObj;
    import com.cicdi.servertemplate.common.model.RetCode;
    import com.cicdi.servertemplate.common.util.VCodeUtil;
    import com.cicdi.servertemplate.modules.sys.dao.ITokenMapper;
    import com.cicdi.servertemplate.modules.sys.dao.IUserMapper;
    import com.cicdi.servertemplate.modules.sys.model.LoginInfo;
    import com.cicdi.servertemplate.modules.sys.model.Token;
    import com.cicdi.servertemplate.modules.sys.model.UserModel;
    
    import com.cicdi.servertemplate.modules.sys.service.SecurityService;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.security.authentication.AnonymousAuthenticationToken;
    import org.springframework.security.authentication.AuthenticationManager;
    import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
    import org.springframework.security.core.Authentication;
    import org.springframework.security.core.context.SecurityContextHolder;
    import org.springframework.security.core.userdetails.UserDetails;
    import org.springframework.security.crypto.password.PasswordEncoder;
    import org.springframework.transaction.annotation.Transactional;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;
    import org.springframework.web.bind.annotation.RequestParam;
    import org.springframework.web.bind.annotation.RestController;
    
    import java.util.Date;
    import java.util.UUID;
    
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import javax.servlet.http.HttpSession;
    
    /**
     * Created by LOG on 2017/3/27.
     */
    @RestController
    @RequestMapping("/security")
    public class SecurityController {
    
    
        @Autowired
        public SecurityService securityService;
    
    
        private Logger log = LoggerFactory.getLogger(SecurityController.class);
    
        /**
         * 修改密码
         *
         * @param userId 用户ID
         * @param newPassword 新密码
         * @return
         */
        @RequestMapping(value = "/changePwd", method = RequestMethod.POST)
        public ResponseObj<Boolean> changePwd(@RequestParam String userId,
                                              @RequestParam String oldPassword,
                                              @RequestParam String newPassword) throws BusinessException {
    
            boolean result = securityService.changePassword(userId, oldPassword, newPassword);
            return new ResponseObj<>(result, RetCode.SUCCESS);
        }
    
        /**
         * 通过密码登录
         * @param pwd 密码
         * @param userId  用户名
         * @param deviceId  设备ID,
         * @param vcode 验证码
         * @param request
         * @return
         * @throws Exception
         */
        @RequestMapping(value = "/loginByPwd", method = RequestMethod.POST)
        public ResponseObj<LoginInfo> loginByPwd(@RequestParam("password") String pwd,
                                                 @RequestParam String userId,
                                                 @RequestParam String deviceId,
                                                 @RequestParam(required = false) String vcode,
                                                 HttpServletRequest request) throws Exception {
            //有时候存在带着上一次的sessionId来访问服务导致无法登陆的问题, 也就是重复登录的问题,这里临时这样解决
    //        mustNoLogin(request);
    
    //        if (session.getAttribute("vcode") == null || !session.getAttribute("vcode").equals(vcode.toLowerCase())) {
    //            throw new BusinessException("图片验证码输入错误");
    //        }
    
            //防止重复登录
            if(!(SecurityContextHolder.getContext().getAuthentication().getPrincipal() instanceof  UserModel)) {
    
                if (pwd == null || pwd.equals("")) {
                    throw new BusinessException("用户密码不能为空");
                }
    
                request.login(userId, pwd);
            }
            UserModel user = (UserModel)
                    SecurityContextHolder.getContext().getAuthentication().getPrincipal();
            Token newToken = new Token();
            newToken.setUserId(user.getUserId());
            newToken.setAppCode(deviceId);
            String token = securityService.genToken(newToken);
            return new ResponseObj<>(new LoginInfo(user, token), RetCode.SUCCESS);
        }
    
    
        @RequestMapping(value = "/loginByToken", method = RequestMethod.POST)
        public ResponseObj<LoginInfo> loginWithToken(@RequestParam String userId,
                                                     @RequestParam String deviceId,
                                                     @RequestParam String token,
                                                     HttpServletRequest request) throws BusinessException {
            //mustNoLogin(request);
            Token tokenModel = securityService.getToken(token, userId, deviceId);
            if (tokenModel == null) {
                throw new BusinessException("凭证无效, 自动登录失败");
            }
            if (new Date().getTime() - tokenModel.getCreateTime() < 1000 * 60 * 60 * 24 * 15) {
                securityService.loginAnyCondition(userId);
                UserModel user = (UserModel) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
                Token newToken = new Token();
                newToken.setUserId(userId);
                newToken.setAppCode(deviceId);
                String genToken = securityService.genToken(newToken);
                return new ResponseObj<>(new LoginInfo(user, genToken), RetCode.SUCCESS);
            } else {
                throw new BusinessException("凭证超时,请重新登陆");
            }
        }
    
    
        /**
         * 退出系统
         *
         * @param request
         * @return
         */
        @RequestMapping(value = "/logout", method = RequestMethod.POST)
        public ResponseObj<Boolean> logout(HttpServletRequest request) throws Exception {
            UserModel user = (UserModel) SecurityContextHolder
                    .getContext().getAuthentication().getPrincipal();
            request.logout();
            securityService.deleteToken(user.getUserId());
            return new ResponseObj<>(true, RetCode.SUCCESS);
        }
    
    
        /**
         * 更新权限
         *
         * @return
         */
        @RequestMapping(value = "/updateAuthority", method = RequestMethod.GET)
        public ResponseObj<Boolean> updateAuthority() {
            securityService.updateAuthority();
            return new ResponseObj<>(true, RetCode.SUCCESS);
        }
    
        /**
         * 获取验证码接口
         *
         *
         * @param request
         * @param response
         * @throws Exception
         */
        @RequestMapping(value = "/vcode", method = RequestMethod.GET)
        public void getVCode(HttpServletRequest request, HttpServletResponse response) throws
                Exception {
    
            mustNoLogin(request);
            HttpSession session = request.getSession();
    
            response.setHeader("Pragma", "No-cache");
            response.setHeader("Cache-Control", "no-cache");
            response.setDateHeader("Expires", 0);
            response.setContentType("image/jpeg");
            String verifyCode = VCodeUtil.generateVerifyCode(4);
            log.debug(request.getRemoteAddr() + "获取验证码" + verifyCode);
            session.setAttribute("vcode", verifyCode.toLowerCase());
            int w = 100, h = 30;
            VCodeUtil.outputImage(w, h, response.getOutputStream(), verifyCode);
        }
    
    
        private void mustNoLogin(HttpServletRequest request) {
            //有时候存在带着上一次的sessionId来访问服务导致无法登陆的问题, 也就是重复登录的问题,这里临时这样解决
            try {
                if (SecurityContextHolder.getContext().getAuthentication().isAuthenticated()
                        && !(SecurityContextHolder.getContext().getAuthentication() instanceof
                        AnonymousAuthenticationToken))
                    request.logout();
            } catch (Exception ex) {
    
            }
        }
    
    
        private boolean hasLogin(HttpServletRequest request){
            if (SecurityContextHolder.getContext().getAuthentication().isAuthenticated() &&
                    SecurityContextHolder.getContext().getAuthentication().getPrincipal() instanceof  UserModel){
                return true;
            }
            return false;
        }
    
    }
    
    

    SecurityConfig

    package com.cicdi.servertemplate.common.config.security;
    
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.boot.autoconfigure.security.Http401AuthenticationEntryPoint;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.security.access.AccessDecisionVoter;
    import org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl;
    import org.springframework.security.access.vote.RoleHierarchyVoter;
    import org.springframework.security.access.vote.UnanimousBased;
    import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
    import org.springframework.security.config.annotation.web.builders.HttpSecurity;
    import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
    import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
    import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer;
    import org.springframework.security.crypto.password.PasswordEncoder;
    import org.springframework.security.crypto.password.StandardPasswordEncoder;
    import org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler;
    import org.springframework.security.web.access.expression.WebExpressionVoter;
    import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;
    
    import java.util.ArrayList;
    import java.util.List;
    
    /**
     * Created by LOG on 2017/3/6.
     */
    @Configuration
    @EnableWebSecurity
    public class SecurityConfig extends WebSecurityConfigurerAdapter {
    
    
        //PermissionEvaluator
    
        @Value("${spring.profiles.active}")
        protected String envActive;
    
        @Autowired
        private SpringUserDetailsService userDetailsService;
    
        @Autowired
        SpringCacheModuleSecurity springCacheModuleSecurity;
    
        @Autowired
        SpringCacheRoleHierarchy springCacheRoleHierarchy;
    
    
        //密码加密对象
        @Bean
        public PasswordEncoder passwordEncoder() {
            if (envActive.equals("prod")) {  //生产环境下加密方式
                return new StandardPasswordEncoder();
            } else {
    //            return NoOpPasswordEncoder.getInstance();
                return new StandardPasswordEncoder();
            }
        }
    
    
        //表达式
        @Bean
        public DefaultWebSecurityExpressionHandler expressionHandler() {
            DefaultWebSecurityExpressionHandler expressionHandler = new DefaultWebSecurityExpressionHandler();
            expressionHandler.setRoleHierarchy(roleHierarchy());
    
            return expressionHandler;
        }
    
    
        //决策管理 Voter
        //如果mrVoter否决了, 则直接否决,
        //mrVoter不表决或者同意了。 则进行webExpressionVoter表决, 即下方代码configure配置
        //一般configure配置的   数据库表中就不应该再配置了, 否则数据库表中配置了, 则configure就不要配置了
        //通常 configure 只是检验是否登陆和 静态资源全通过
        @Bean
        @SuppressWarnings(value = {"rawtypes"})
        public UnanimousBased accessDecisionManager() {
            List<AccessDecisionVoter<? extends Object>> decisionVoters = new ArrayList<AccessDecisionVoter<? extends
                    Object>>();
            WebExpressionVoter webExpressionVoter = new WebExpressionVoter();
            webExpressionVoter.setExpressionHandler(expressionHandler());
    
            MRVoter mrVoter = new MRVoter();
            mrVoter.setRoleHierarchy(roleHierarchy());
            mrVoter.setSpringCacheModuleSecurity(springCacheModuleSecurity);
    
            decisionVoters.add(mrVoter);
            decisionVoters.add(webExpressionVoter);
            UnanimousBased unanimousBased = new UnanimousBased(decisionVoters);
            unanimousBased.setAllowIfAllAbstainDecisions(false);
            return unanimousBased;
        }
    
        public RoleHierarchyVoter roleVoter() {
            return new RoleHierarchyVoter(roleHierarchy());
        }
    
        @Bean
        public RoleHierarchyImpl roleHierarchy() {
            return springCacheRoleHierarchy;
        }
    
        @Autowired
        protected void configure(AuthenticationManagerBuilder auth) throws Exception {
            auth
                    //.authenticationProvider(new SpringAuthenticationProvider())
                    //.eraseCredentials(false)
                    .userDetailsService(userDetailsService)
                    //对password进行加密
                    .passwordEncoder(passwordEncoder());
        }
    
        @Bean
        public Http401AuthenticationEntryPoint securityException401EntryPoint() {
    
            return new Http401AuthenticationEntryPoint("");
        }
    
    
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry
                    expressionInterceptUrlRegistry = http.exceptionHandling().authenticationEntryPoint
                    (securityException401EntryPoint())
                    .and()
                    .csrf()
                    .disable()
                    .headers()
                    .frameOptions()
                    .sameOrigin()
                    .and()
                    .logout().addLogoutHandler(new SecurityContextLogoutHandler())
                    .and()
                    .authorizeRequests()
    
    //                .antMatchers(HttpMethod.POST, "/v1/ftpConfig/test").permitAll()
    //                .antMatchers(HttpMethod.POST, "/v1/databaseConfig/test").permitAll()
    
                    .antMatchers("/security/loginByPwd").permitAll()
                    .antMatchers("/security/loginByToken").permitAll()
                    .antMatchers("/security/vcode").permitAll();
    
    
            //正式环境下所有的请求都要经过验证
            if (envActive.equals("prod")) {
                expressionInterceptUrlRegistry.accessDecisionManager(accessDecisionManager()).anyRequest().authenticated();
            } else {
                expressionInterceptUrlRegistry.anyRequest().permitAll();
            }
    //                .permitAll()  //权限允许所有人
    //                .and()
    //                .sessionManagement()
    //                .invalidSessionUrl("/login")
    //                .maximumSessions(5)
    
    
        }
    
    }
    
    
    

    相关文章

      网友评论

          本文标题:Caused by: org.springframework.s

          本文链接:https://www.haomeiwen.com/subject/bfkxxqtx.html