zoukankan      html  css  js  c++  java
  • SpringBoot第六篇-SpringBoot+Mybatis+SpringSecurity+JWT整合,开发工具IDea

    1、新建SpringBoot项目,选择Maven,插件选择SpringWeb、SpringSecurity、Mysql Driver、Mybatis Framwork

    2、创建controller,看看能否跑通,先设置配置文件application.yml的端口为8094,不喜欢用8080,因为太多程序调试使用它

    server:
    port: 8094
    spring:
    datasource:
    username: root
    password: root
    url: jdbc:mysql://localhost/8888?characterEncoding=utf-8&useSSl=false
    driver-class-name: com.mysql.jdbc.Driver
    mybatis:
    mapper-locations: classpath*:mappers/*Mapper.xml
    type-aliases-package: cn.yinmingneng.yinmingneng.entities
    configuration:
    map-underscore-to-camel-case: true
    @RestController
    public class TestController {
    
        @RequestMapping("/gethello")
        public String getHello(){
            return "你好!";
    
        }
    
    }
    

     3、输入地址:http://localhost:8094/gethello,出现一下界面表示配置成功了

      用户名:user,密码:

     输入以后登陆成功跳转到

     4、创建数据库表SysUser表,里面包含ID,username,password,rolename字段

     5、创建实体,放到entities包下面

    package cn.yinmingneng.yinmingneng.entities;
    
    public class SysUser {
    
        private  Integer id;
    
        public Integer getId() {
            return id;
        }
    
        public void setId(Integer id) {
            this.id = id;
        }
    
        public String getUsername() {
            return username;
        }
    
        public void setUsername(String username) {
            this.username = username;
        }
    
        public String getPassword() {
            return password;
        }
    
        public void setPassword(String password) {
            this.password = password;
        }
    
        public String getRolename() {
            return rolename;
        }
    
        public void setRolename(String rolename) {
            this.rolename = rolename;
        }
    
        private  String username;
        private  String password;
        private  String rolename;
    }
    

     

    6、创建usermapper对象,用于自动生成sysuser表的增删改查语句,此类是个接口,通过java动态代理生成,我使用配置文件生成增删改查语句

    @Mapper
    public interface SysUserMapper  {
    
        /**
         *  添加用户
         * @param sysUser
         * @return
         */
         int insertSysUser(SysUser sysUser);
    
        /**
         * 更新
         * @param sysUser
         * @return
         */
         int  updateSysUser(SysUser sysUser);
    
        /**
         * 删除用户
         * @return
         */
         int deleteSysUserById(Integer id);
    
         SysUser getAll(String userName);
    
    }
    

    7、编写映射的SysUserMapper.XML文件,id和接口的方法名一样,否则会报错,映射不到

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE mapper
            PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <mapper namespace="cn.yinmingneng.yinmingneng.mapper.SysUserMapper"   >
    
    
    
        <sql id="selectSysUser"  >
            SELECT id ,username,password,rolename FROM sysuser
        </sql>
    
    
    
        <select id="getAll" parameterType="String" resultType="SysUser">
            SELECT id ,username,password,rolename FROM sysuser where username = #{username}
        </select>
    
        <insert id="insertSysUser" parameterType="SysUser"  >
            insert into sysuser (
            <if test="username != null and username != '' ">username,</if>
            <if test="password != null and password != '' ">password,</if>
            <if test="rolename != null and rolename != '' ">config_value,</if>
            )values(
            <if test="username != null and username != ''">#{username},</if>
            <if test="password != null and password != ''">#{password},</if>
            <if test="rolename != null and rolename != ''">#{rolename},</if>
            )
        </insert>
    
        <update id="updateSysUser" parameterType="SysUser">
            update sysuser
            <set>
                <if test="username != null and username != ''">username = #{username},</if>
                <if test="password != null and password != ''">password = #{password},</if>
                <if test="rolename != null and rolename != ''">rolename = #{rolename}</if>
            </set>
            where id = #{id}
        </update>
    
        <delete id="deleteSysUserById"  parameterType="Integer">
            delete  from sysuser where id = #{id}
        </delete>
    
    
    </mapper>
    

     8、服务层SysUserService代码,接口,方便接口化编程

    package cn.yinmingneng.yinmingneng.Services;
    
    import cn.yinmingneng.yinmingneng.entities.SysUser;
    import org.springframework.stereotype.Service;
    
    import java.util.List;
    
    
    
    public interface SysUserService {
    
        /**
         *  添加用户
         * @param sysUser
         * @return
         */
        public int insertSysUser(SysUser sysUser);
    
        /**
         * 更新
         * @param sysUser
         * @return
         */
        public int  updateSysUser(SysUser sysUser);
    
        /**
         * 删除用户
         * @return
         */
        public  int deleteSysUserById();
    
        public SysUser getAll(String userName);
    }
    

     9、服务层实现类,SysUserServiceImpl

    package cn.yinmingneng.yinmingneng.Services.ServiceIml;
    
    import cn.yinmingneng.yinmingneng.Services.SysUserService;
    import cn.yinmingneng.yinmingneng.entities.SysUser;
    import cn.yinmingneng.yinmingneng.mapper.SysUserMapper;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    
    import java.util.List;
    
    @Service
    public class SysUserServiceImpl implements SysUserService {
    
        @Autowired
        SysUserMapper sysUserMapper;
    
        @Override
        public int insertSysUser(SysUser sysUser) {
            return   sysUserMapper.insertSysUser(sysUser);
        }
    
        @Override
        public int updateSysUser(SysUser sysUser) {
            return sysUserMapper.updateSysUser(sysUser);
        }
    
        @Override
        public int deleteSysUserById() {
            return 0;
        }
    
        @Override
        public SysUser getAll(String userName) {
    
            return sysUserMapper.getAll(userName);
        }
    }
    

    10、控制器测试层,永远测试带权限功能,不带权限功能,是否登录功能,匿名访问功能

    package cn.yinmingneng.yinmingneng.Controller;
    
    import cn.yinmingneng.yinmingneng.Services.SysUserService;
    import cn.yinmingneng.yinmingneng.entities.SysUser;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.security.access.prepost.PreAuthorize;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    import java.util.List;
    @RestController
    public class TestController {
    
        @Autowired
        SysUserService sysUserService;
    
        @RequestMapping("/gethello")
        public String getHello(){
            return "你好!";
    
        }
        /**
         *  添加用户
         * @param sysUser
         * @return
         */
        @RequestMapping("/insertsysuser")
         public int insertSysUser(SysUser sysUser)
        {
             return sysUserService.insertSysUser(sysUser);
         }
    
        /**
         * 更新
         * @param sysUser
         * @return
         */
        @RequestMapping("/a/updatesysuser")
        @PreAuthorize("hasRole('ROLE_USER')")
        public String  updateSysUser(SysUser sysUser){
            return "sucessUpdateSysUser";
        }
        @RequestMapping("/a/getall")
       public  SysUser getAll(String userName){
    
            return  sysUserService.getAll(userName);
       }
    
    }
    

      

    11、编写userdetailservie的实现类,该类用于实现userdetail对象,用于验证账号和密码

    package cn.yinmingneng.yinmingneng.config;
    
    import cn.yinmingneng.yinmingneng.Services.SysUserService;
    import cn.yinmingneng.yinmingneng.entities.SysUser;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.security.core.GrantedAuthority;
    import org.springframework.security.core.authority.SimpleGrantedAuthority;
    import org.springframework.security.core.userdetails.User;
    import org.springframework.security.core.userdetails.UserDetails;
    import org.springframework.security.core.userdetails.UserDetailsService;
    import org.springframework.security.core.userdetails.UsernameNotFoundException;
    import org.springframework.stereotype.Service;
    
    import java.util.ArrayList;
    import java.util.Collection;
    import java.util.List;
    @Service
    public class UserDetailimpl implements UserDetailsService {
        @Autowired
        private SysUserService sysUserService;
        /**
         * 从数据库获取用户数据
         * @param s
         * @return
         * @throws UsernameNotFoundException
         */
        @Override
        public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
    
            Collection<GrantedAuthority> authorities = new ArrayList<>();
            SysUser user = sysUserService.getAll(s);
            // 判断用户是否存在
            if(user == null) {
                throw new UsernameNotFoundException("用户名不存在");
            }
            if(user.getUsername() != null && user.getUsername()!="")
            authorities.add(new SimpleGrantedAuthority(user.getRolename()));
            // 返回UserDetails实现类
            return new User(user.getUsername(), user.getPassword(), authorities);
        }
    }
    

    12、登录认证功能,spingSecutiry提供登录认证功能,请求/login会触发该方法,使用post请求

    package cn.yinmingneng.yinmingneng.filters;
    
    import cn.yinmingneng.yinmingneng.Services.TokenService;
    import cn.yinmingneng.yinmingneng.entities.SysUser;
    import com.fasterxml.jackson.databind.deser.impl.JavaUtilCollectionsDeserializers;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.security.authentication.AuthenticationManager;
    import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
    import org.springframework.security.core.Authentication;
    import org.springframework.security.core.AuthenticationException;
    import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
    import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
    
    import javax.servlet.FilterChain;
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    import java.util.Collection;
    import java.util.Collections;
    import java.util.HashMap;
    import java.util.Map;
    
    /**
     * 此类用于登录认证,有/login触发,需要post请求
     */
    public class loginfilter   extends UsernamePasswordAuthenticationFilter {
        @Autowired
        private AuthenticationManager authenticationManager;
    
        public loginfilter(AuthenticationManager a){
            this.authenticationManager = a;
        }
        /**
         * 验证账号和密码
         * @param request
         * @param response
         * @return
         * @throws AuthenticationException
         */
        @Override
        public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
    
            String username= request.getParameter("username");
            String password = request.getParameter("password");
            //
           // return super.attemptAuthentication(request, response);
            //验证账号和密码
          return    authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(username,password,
                  Collections.emptyList()));
        }
    
        /**
         * 认证成功,生成token,返回token
         * @param request
         * @param response
         * @param chain
         * @param authResult
         * @throws IOException
         * @throws ServletException
         */
        @Override
        protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response,
                                                FilterChain chain, Authentication authResult) throws IOException, ServletException {
         //   super.successfulAuthentication(request, response, chain, authResult);
    
            request.setCharacterEncoding("UTF-8");
            response.setCharacterEncoding("UTF-8");
    
            String username= request.getParameter("username");
            Map<String,Object> map = new HashMap<>();
         //   map.put("id",sysUser.getId());
            map.put(TokenService.userKey,username);
           // map.put(TokenService.userKey,)
            String token =  TokenService.CreateToken(map);
            response.getWriter().write("认证成功,token:"+token);
        }
    }
    

    13、生成token,我使用了前后端分离功能,所以需要生成token,写了TokenService类,用于解析生成token

    package cn.yinmingneng.yinmingneng.Services;
    import io.jsonwebtoken.Jwts;
    import io.jsonwebtoken.SignatureAlgorithm;
    import org.springframework.stereotype.Component;
    import java.util.Date;
    import java.util.HashMap;
    import java.util.Map;
    import java.util.concurrent.TimeUnit;
    public class TokenService {
        public static  String userKey="user_id";
        private  static  String signKey="rererrertretretrettretert";
    
        public static String CreateToken(Map<String, Object> map) {
            Date now = new Date(System.currentTimeMillis());
            String token = Jwts.builder()
                    .setClaims(map) // 设置自定义数据
                  //  .setIssuedAt(now) // 设置签发时间
                    .setExpiration(new Date(System.currentTimeMillis()+ 1000*60*60*360)) // 设置过期时间
                    //.setIssuer(issuer) // 设置签发者
                   // .setSubject(subject) // 设置面向用户
                    .signWith(SignatureAlgorithm.HS512, signKey)
                    .compact();
            return  token;
        }
    
        /**
         * 解压token,获取里面的令牌,
         * 自动判断有效期
         */
        public static Map parseToken(String t) {
            try {
                return Jwts.parser()
                        .setSigningKey(signKey)
                        .parseClaimsJws(t.replace("Bearer ", ""))
                        .getBody();
            } catch (Exception e) {
                throw new IllegalStateException("Token验证失败:" + e.getMessage());
            }
        }
    }
    

     13、携带token判断权限,token,用于判断token,判断成功就写入角色权限,该类无法自动注入SysUserService,需要手工注入,手工注入的代码在下面

    BasicAuthenticationFilter 该类继承了oprefilter过滤器
    package cn.yinmingneng.yinmingneng.filters;

    import cn.yinmingneng.yinmingneng.Services.SysUserService;
    import cn.yinmingneng.yinmingneng.Services.TokenService;
    import cn.yinmingneng.yinmingneng.Utils.BeanFactoryUtil;
    import cn.yinmingneng.yinmingneng.entities.SysUser;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException;
    import org.springframework.security.authentication.AuthenticationManager;
    import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
    import org.springframework.security.core.GrantedAuthority;
    import org.springframework.security.core.authority.SimpleGrantedAuthority;
    import org.springframework.security.core.context.SecurityContextHolder;
    import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
    import org.springframework.stereotype.Component;
    import org.springframework.util.AntPathMatcher;
    import org.springframework.util.PathMatcher;

    import javax.servlet.FilterChain;
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    import java.util.ArrayList;
    import java.util.Collection;
    import java.util.List;
    import java.util.Map;
    public class JwtAuthenticationFilter extends BasicAuthenticationFilter {
    private static final PathMatcher pathMatcher = new AntPathMatcher();
    private SysUserService sysUserService;

    public JwtAuthenticationFilter(AuthenticationManager authenticationManager) {
    super(authenticationManager);
    }

    //认证token
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
    throws ServletException, IOException {

    String token = request.getHeader("Authorization");
    if (token != null) {
    //验证token,并且写入权限

    Map map = TokenService.parseToken(token);
    String username = (String) map.get(TokenService.userKey);
    if (username != null) {

    //无法自动注入,只能手工注入,不知道为啥
    sysUserService= BeanFactoryUtil.getBean(SysUserService.class);
    SysUser sysUser = sysUserService.getAll(username);

    // 这里直接注入角色,因为JWT已经验证了用户合法性,所以principal和credentials直接为null即可
    List<GrantedAuthority> list = new ArrayList<>();
    list.add(new SimpleGrantedAuthority(sysUser.getRolename()));
    UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(sysUser,
    null, list);

    // 如果验证失败,设置异常;否则将UsernamePasswordAuthenticationToken注入到框架中
    if (authentication == null) {
    //手动设置异常
    request.getSession().setAttribute("SPRING_SECURITY_LAST_EXCEPTION",
    new AuthenticationCredentialsNotFoundException("权限认证失败"));
    // 转发到错误Url
    request.getRequestDispatcher("/login/error").forward(request, response);
    } else {
    SecurityContextHolder.getContext().setAuthentication(authentication);
    filterChain.doFilter(request, response);
    }
    }
    filterChain.doFilter(request, response);
    }
    }
    }

    /**
     * 手工获取注入对象
     */
    
    @Component
    public class BeanFactoryUtil implements ApplicationContextAware {
        private static ApplicationContext context = null;
    
        public static <T> T getBean(Class<T> type) {
            return context.getBean(type);
        }
    
        @Override
        public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
            if (BeanFactoryUtil.context == null) {
                BeanFactoryUtil.context = applicationContext;
            }
        }
    }
    

      

    14、springboot 接口时间映射处理,如果不处理会提示 bad request,"Bad Request",时间处理配置,此时就不用转换date了,直接映射成date

    /*
    *  增加时间处理格式,否则接口无法映射时间,会报错
    * */
    @Configuration
    public class WebMvcConfigurerIMP implements WebMvcConfigurer {
        /**
         * 自动转换时间格式
         *
         * @param registry date
         */
        @Override
        public void addFormatters(FormatterRegistry registry) {
            registry.addFormatter(new DateFormatter("yyyy-MM-dd HH:mm:ss"));
        }
    }
    

    15、用户密码是增加加密方式,注册的时候也需要加密方式,加密方式配置,配置文件配置,注册的时候密码也需要增加加密

        //使用加密方式
               auth.userDetailsService(userDetailimpl).passwordEncoder(bCryptPasswordEncoder());
    
       @PostMapping("/insertsysuser")
         public int insertSysUser(SysUser sysUser) throws ParseException {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
          //  Date date =sdf.parse("2021-1-1 09:35:00");
            BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
            sysUser.setPassword( passwordEncoder.encode(sysUser.getPassword()));
          //  sysUser.setCreatetime(date);
            return sysUserService.insertSysUser(sysUser);
         }
    

    16、Springboot 登录认证失败处理类,该类主要用于验证失败返回错误信息

    @Component
    public class AuthenticationEntryPointImpl implements AuthenticationEntryPoint, Serializable
    {
        private static final long serialVersionUID = -8970718410437077606L;
    
        @Override
        public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException e)
                throws IOException
        {
            int code = HttpStatus.UNAUTHORIZED;
            String msg = StringUtils.format("请求访问:{},认证失败,无法访问系统资源", request.getRequestURI());
            ServletUtils.renderString(response, JSON.toJSONString(AjaxResult.error(code, msg)));
        }
    }
    

      

  • 相关阅读:
    linux 修改 properties
    用Python串口实时显示数据并绘图pyqtgraph
    Python pip国内源
    设计模式之享元模式
    阿里云数据库李飞飞:云计算推动数据库向云原生快速演进
    不懂代码,他怎么开发了20多个政务应用?
    2021十大科技趋势来了!阿里巴巴达摩院全新发布
    2020年勒索病毒事件盘点及未来发展趋势
    一文详解 Nacos 高可用特性
    “让专业的人做专业的事”,畅捷通与阿里云的云原生故事 | 云原生 Talk
  • 原文地址:https://www.cnblogs.com/topguntopgun/p/15501677.html
Copyright © 2011-2022 走看看