进销存系统_SpringSecurity权限框架&登录&用户密码加密&退出

Posted 上善若水

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了进销存系统_SpringSecurity权限框架&登录&用户密码加密&退出相关的知识,希望对你有一定的参考价值。

代码地址:https://gitee.com/bitaotao/jxc-mgmt-par.git

一、引入SpringSecurity权限框架

为了快速方便实现进销存系统权限管理功能,系统引入SpringSecurity框架对应用权限进行统一控制。

1.1、使用SpringSecurity完成用户登录认证

1.1.1、jxc-admin pom.xml引入SpringSecurity坐标

        <!--spring security 组件-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>

1.1.2、JxcAuthenticationSuccessHandler.java

package com.xbmu.admin.config.security;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.xbmu.admin.model.RespBean;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
import org.springframework.stereotype.Component;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * 认证成功处理器
 *
 * @author bitaotao
 * @since 2021-09-12
 */
@Component
public class JxcAuthenticationSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler {
    private static ObjectMapper objectMapper = new ObjectMapper();
    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
        response.setContentType("application/json;charset=UTF-8");
        response.getWriter().write(objectMapper.writeValueAsString(
                RespBean.success("登录成功")));
    }
}

1.1.3、JxcAuthenticationFailedHandler.java

package com.xbmu.admin.config.security;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.xbmu.admin.model.RespBean;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
import org.springframework.stereotype.Component;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 *
 * 认证失败处理器
 * @author bitaotao
 * @since 2021-09-12
 */
@Component
public class JxcAuthenticationFailedHandler extends SimpleUrlAuthenticationFailureHandler {
    private static ObjectMapper objectMapper = new ObjectMapper();
    @Override
    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
            response.setContentType("application/json;charset=UTF-8");
            response.getWriter().write(objectMapper.writeValueAsString(
                    RespBean.error("用户名或密码错误")));
    }
}

1.1.4、SpringSecurity配置类 SecurityConfig.java

package com.xbmu.admin.config.security;

import com.xbmu.admin.pojo.User;
import com.xbmu.admin.service.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

import javax.annotation.Resource;

/**
 * SpringSecurity配置类
 * @author bitaotao
 * @since 2021-09-12
 */
@SpringBootConfiguration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private JxcAuthenticationSuccessHandler jxcAuthenticationSuccessHandler;

    @Autowired
    private JxcAuthenticationFailedHandler jxcAuthenticationFailedHandler;

    @Resource
    private IUserService userService;

    /**
     * 放行静态资源
     * @param web
     * @throws Exception
     */
    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers(
                "/images/**",
                "/css/**",
                "/js/**",
                "/lib/**",
                "/error/**");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // 禁用csrf
        http.csrf().disable()
                // 允许frame 页面嵌套
                .headers().frameOptions().disable()
                .and()
                    .formLogin()
                    .usernameParameter("userName")
                    .passwordParameter("passWord")
                    .loginPage("/index")
                    .loginProcessingUrl("/login")
                    .successHandler(jxcAuthenticationSuccessHandler)
                    .failureHandler(jxcAuthenticationFailedHandler)
                .and()
                    .authorizeRequests().antMatchers("/index","/login").permitAll()
                    .anyRequest().authenticated();

    }

    @Bean
    protected UserDetailsService userDetailsService() {
        return new UserDetailsService() {
            @Override
            public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException {
                // 根据用户名查询用户记录
                User userDetails = userService.findUserByUserName(userName);
                return userDetails;
            }
        };
    }

    /**
     * 配置 SpringSecurity 密码加密 Bean对象
     * @return
     */
    @Bean
    public PasswordEncoder encoder(){
        return new BCryptPasswordEncoder();
    }

    /**
     * 配置认证Service接口与密码加密实现类
     * @param auth
     * @throws Exception
     */
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService()).passwordEncoder(encoder());
    }
}

1.1.5、User.java

package com.xbmu.admin.pojo;

import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import java.io.Serializable;
import java.util.Collection;

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

/**
 * <p>
 * 用户表
 * </p>
 *
 * @author bitaotao
 * @since 2021-09-11
 */
@Data
@EqualsAndHashCode(callSuper = false)
@TableName("t_user")
@ApiModel(value="User对象", description="用户表")
public class User implements Serializable, UserDetails {

    private static final long serialVersionUID = 1L;

    @ApiModelProperty(value = "主键id")
    @TableId(value = "id", type = IdType.AUTO)
    private Integer id;

    @ApiModelProperty(value = "备注名")
    private String bz;

    @ApiModelProperty(value = "密码")
    private String password;

    @ApiModelProperty(value = "真实姓名")
    private String trueName;

    @ApiModelProperty(value = "用户名")
    private String userName;

    @ApiModelProperty(value = "备注")
    private String remarks;

    @ApiModelProperty(value = "是否删除")
    private Integer isDel;

    @TableField(exist = false)
    Collection<? extends GrantedAuthority> authorities;

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return this.authorities;
    }

    @Override
    public String getUsername() {
        return userName;
    }

    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }

    @Override
    public boolean isEnabled() {
        return true;
    }
}

1.1.6、UserController.java

删除UserController类中的login方法,引入了SpringSecurity框架,采用了SpringSecurity框架中的login方法。

1.1.7、UserServiceImpl.java

将该类中 user.getUserName()代码 修改为 user.getUsername()。因为user类实现了org.springframework.security.core.userdetails.UserDetails接口,所有就采用UserDetails接口中的方法。

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package org.springframework.security.core.userdetails;

import java.io.Serializable;
import java.util.Collection;
import org.springframework.security.core.GrantedAuthority;

public interface UserDetails extends Serializable {
    Collection<? extends GrantedAuthority> getAuthorities();

    String getPassword();

    String getUsername();

    boolean isAccountNonExpired();

    boolean isAccountNonLocked();

    boolean isCredentialsNonExpired();

    boolean isEnabled();
}

1.1.8、测试

登录后,没有进入首页,而是又回到了登录页面。这是因为之前写的非法访问控制起了作用。

解决方法:删除非法访问控制代码(拦截器)。

<a href="javascript:;">${(Session.SPRING_SECURITY_CONTEXT.authentication.principal.username)!''}</a>


1.2、用户密码加密

1.2.1、密码修改对明文密码加密处理

使用SpringSecurity框架实现用户登录时,主要通过PasswordEncoder接口实现用户密码加密处理,核心实现类BCryptPasswordEncoder常用方法:

方法名描述
String encode(CharSequence rawPassword)字符串序列加密
boolean matches(CharSequence rawPassword, String encodedPassword)密码匹配,参数1为明文密码,参数2为加密密码,匹配成功返回true,反之false

1.2.2、删除自定义的login方法

删除UserServiceImpl.java、IUserService.java类中的login方法

1.2.3、UserController.java

修改UserController类中updateUserPassword方法

   /**
     * 用户密码更新
     * @param principal principal对象
     * @param oldPassword 旧密码
     * @param newPassword 新密码
     * @param confirmPassword 确认密码
     * @return
     */
    @RequestMapping("updateUserPassword")
    @ResponseBody
    public RespBean updateUserPassword(Principal principal, String oldPassword, String newPassword, String confirmPassword){
        userService.updateUserPassword(principal.getName(),oldPassword,newPassword,confirmPassword);
        return RespBean.success("用户密码更新成功!");
    }

1.2.4、UserServiceImpl.java

package com.xbmu.admin.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.xbmu.admin.pojo.User;
import com.xbmu.admin.mapper.UserMapper;
import com.xbmu.admin.service.IUserService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xbmu.admin.util.AssertUtil;
import com.xbmu.admin.util.StringUtil;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;

/**
 * <p>
 * 用户表 服务实现类
 * </p>
 *
 * @author bitaotao
 * @since 2021-09-11
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {

    @Resource
    private PasswordEncoder passwordEncoder;

    @Override
    public User findUserByUserName(String userName) {
        return this.baseMapper.selectOne(new QueryWrapper<User>().eq("is_del",0).eq("user_name",userName));
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
    public void updateUserInfo(User user) {
        /**
         * 用户名:非空、唯一
         */
        AssertUtil.isTrue(StringUtil.isEmpty(user.getUsername()),"用户名不能为空!");
        User tempUser = this.findUserByUserName(user.进销存系统_系统权限管理-用户&角色管理

进销存系统_系统权限管理-用户&角色管理

进销存系统_角色和资源管理(13)

项目一众筹网07_01_SpringSecurity框架简介和用法SpringSecurity负责的是 权限验证Spring的注解模式maven引入Spring环境加入layUI环境

[SpringSecurity]web权限方案_自动登陆_原理分析和具体实现

项目一学习框架SpringSecurity08_00_权限控制@Component放到IOC容器里面带盐值的加密