SpringBoot JWT+SpringSecurity权限管理,使用JSON交互

SpringBoot JWT+SpringSecurity权限管理,使用JSON交互

什么是SpringSecurity

Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架。它提供了一组可以在Spring应用上下文中配置的Bean,充分利用了Spring IoC,DI(控制反转Inversion of Control ,DI:Dependency Injection 依赖注入)和AOP(面向切面编程)功能,为应用系统提供声明式的安全访问控制功能,减少了为企业系统安全控制编写大量重复代码的工作。

多的就不做介绍了,这个框架大家应该都很明白,直接步入正题吧!
此篇只写了JWT怎么和Security怎么整合在一起的流程作为笔记。想了解JWT的可去我的博客JWT 这篇有细致讲解。

一、建立数据库

首先创建对应数据库:
user 存放用户
SpringBoot JWT+SpringSecurity权限管理,使用JSON交互_第1张图片
role存放所有权限

SpringBoot JWT+SpringSecurity权限管理,使用JSON交互_第2张图片
user_role 存放用户和权限的关系
SpringBoot JWT+SpringSecurity权限管理,使用JSON交互_第3张图片
menu 存放动态地址
SpringBoot JWT+SpringSecurity权限管理,使用JSON交互_第4张图片
menu_role存放动态地址和权限之间的关系
SpringBoot JWT+SpringSecurity权限管理,使用JSON交互_第5张图片

二、SpringBoot配置

POM

  
            org.springframework.boot
            spring-boot-starter-security
        

        
            io.jsonwebtoken
            jjwt
            0.6.0
        

        
            com.baomidou
            mybatis-plus-boot-starter
            2.3
        
        
            mysql
            mysql-connector-java
            runtime
        

        
            mysql
            mysql-connector-java
            8.0.20
        

        
            com.alibaba
            druid
            1.1.6
        

        
            org.projectlombok
            lombok
            true
        
        
            com.google.code.gson
            gson
            2.8.6
        

        
            com.alibaba
            fastjson
            1.2.54
        

application.properties

server.port=8080

#mysql
spring.datasource.url=jdbc:mysql://192.168.2.113:3306/securitytest?useUnicode=true&characterEncoding=utf8
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.type =com.alibaba.druid.pool.DruidDataSource
mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
#mybatis-plus
mybatis-plus.mapper-locations=classpath:Mapper/*.xml
mybatis-plus.type-aliases-package=com.bxc.securitytest.Entity
mybatis-plus.configuration.map-underscore-to-camel-case: true

三、user实体类

@TableName(value = "user")  //表名
public class User implements UserDetails {
    private int id;
    private String username;
    private String password;
    private Boolean enabled;
    private Boolean locked;
    @TableField(exist = false)
    private List roles;

    @Override
    public Collection getAuthorities() {
        List authorities = new ArrayList<>();
        for (Role role : roles) {
            System.out.println("登录权限:"+role.getRole());
            authorities.add(new SimpleGrantedAuthority(role.getRole()));
        }
        return authorities;
    }

    @Override
    public String getPassword() {
        return password;
    }
    @Override
    public String getUsername() {
        return username;
    }
    @Override
    public boolean isAccountNonExpired() {
        return true;
    }
    @Override
    public boolean isAccountNonLocked() {
        return !locked;
    }
    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }
    @Override
    public boolean isEnabled() {
        return enabled;
    }


    //省略getter/setter

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public void setPassword(String password) {
        this.password = password;
    }

//    public Boolean getEnabled() {
//        return enabled;
//    }

    public void setEnabled(Boolean enabled) {
        this.enabled = enabled;
    }

    public Boolean getLocked() {
        return locked;
    }

    public void setLocked(Boolean locked) {
        this.locked = locked;
    }

    public List getRoles() {
        return roles;
    }

    public void setRoles(List roles) {
        this.roles = roles;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", password='" + password + '\'' +
                ", enabled=" + enabled +
                ", locked=" + locked +
                ", roles=" + roles +
                '}';
    }
}

四、数据库Mapper

@Mapper
@Component
public interface UserMapper extends BaseMapper {
    @Select("select * from user where username = #{username}")
    User findUserFromUsername(String username);

    @Insert("insert into user(username,password,enabled,locked) value(#{username},#{password},#{enabled},#{locked})")
    @Options(useGeneratedKeys = true,keyProperty = "id",keyColumn = "id")
    int addUser(User user);

}
@Mapper
@Component
public interface RoleMapper extends BaseMapper {
    @Select("select a.* from role a,user_role b where a.id = b.roleid and b.userid = #{id}")
    List findRoleFromUserId(int id);

    @Select("select id from role where role = #{rolename}")
    int findRoleIdFromName(String rolename);

    @Insert("insert into user_role(userid,roleid) value(#{userid},#{roleid})")
    int insertUserRole(@Param("userid") int userid, @Param("roleid") int roleid);
}
@Mapper
@Component
public interface MenuMapper {
    List findMenu();
}




    
        
        
        
            
            
            
        
    

    

五、Service

@Service
public class UserService implements UserDetailsService {
    @Autowired
    UserMapper userMapper;
    @Autowired
    RoleMapper roleMapper;

    @Override
    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
        User user = userMapper.findUserFromUsername(s);
        if (user == null) {
            throw new UsernameNotFoundException("账户不存在!");
        }
        user.setRoles(roleMapper.findRoleFromUserId(user.getId()));
        System.out.println(user);
        return user;
    }
}
@Service
@Slf4j
public class RoleService {
    @Autowired
    UserMapper userMapper;
    @Autowired
    RoleMapper roleMapper;
    @Autowired
    MenuMapper menuMapper;

    public boolean AddUser(String username, String password,String role) {
        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder(10);
        String encodePasswod = encoder.encode(password);
        return saveToDb(username, encodePasswod,role);
    }

    @Transactional(propagation = Propagation.REQUIRED)
    public boolean saveToDb(String username, String encodePasswod,String role) {
        User user = new User();
        user.setUsername(username);
        user.setPassword(encodePasswod);
        user.setEnabled(true);
        user.setLocked(false);
        log.info(user.toString());
        System.out.println(user.toString());
        int count = userMapper.addUser(user);
        if (count > 0){
            System.out.println(user.toString());
            int roleid = roleMapper.findRoleIdFromName(role);
            System.out.println(roleid);
            int c = roleMapper.insertUserRole(user.getId(),roleid);
            if (c > 0){
                return true;
            }
        }
        return false;
    }


    public List findMeun(){
        return menuMapper.findMenu();
    }
}

六、重写登录过滤器

public class LoginAuthenticationFilter extends UsernamePasswordAuthenticationFilter {

    @SneakyThrows
    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
        response.setContentType("text/json;charset=utf-8");
        if(request.getContentType().equals(MediaType.APPLICATION_JSON_UTF8_VALUE) ||request.getContentType().equals(MediaType.APPLICATION_JSON_VALUE)){
            BufferedReader br = null;
            try {
                br = new BufferedReader(new InputStreamReader(request.getInputStream(),"utf-8"));
                String line = null;
                StringBuilder sb = new StringBuilder();
                while ((line = br.readLine()) != null) {
                    sb.append(line);
                }
                JSONObject json= JSONObject.parseObject(sb.toString());
                System.out.println(json.toString());

                String username = json.getString("username");
                String password = json.getString("password");

                UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password);
                this.setDetails(request, authRequest);
                return this.getAuthenticationManager().authenticate(authRequest);
            } catch (IOException e) {
                e.printStackTrace();
                response.getWriter().write(JSON.toJSONString(ResSuccessTemplate.builder().code(400).message("参数错误!").build()));
            }
        } else {
            return super.attemptAuthentication(request, response);
        }
        response.getWriter().write(JSON.toJSONString(ResSuccessTemplate.builder().code(400).message("参数错误!").build()));
        return null;
    }

}

七、登录成功Handler

@Component
public class AuthenticationSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler {
    @Autowired
    JWTUtil jwtUtil;

    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
        User user = (User)authentication.getPrincipal();

        String username = user.getUsername();
        List authorities = (List) user.getAuthorities();
        List list = new ArrayList<>();
        String role = "";
        for(GrantedAuthority g : authorities){
            list.add(g.getAuthority());
            role = g.getAuthority();
        }

        String  token = jwtUtil.CreateToken(user.getId()+"",username,role);

        response.setContentType("text/json;charset=utf-8");
        Map map = new HashMap<>();
        map.put("username",username);
        map.put("role",role);
        map.put("token",token);
        response.getWriter().write(JSON.toJSONString(ResSuccessTemplate.builder().data(map).build()));
    }
}

八、登录失败Handler

@Component
public class AuthenticationFailHandler extends SimpleUrlAuthenticationFailureHandler {

    @Override
    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) throws IOException, ServletException {

        response.setContentType("text/json;charset=utf-8");

        if (e instanceof UsernameNotFoundException || e instanceof BadCredentialsException) {

            response.getWriter().write(JSON.toJSONString(ResFailTemplate.builder().code(400).message("用户名或密码错误!").build()));

        } else if (e instanceof DisabledException) {

            response.getWriter().write(JSON.toJSONString(ResFailTemplate.builder().code(400).message("账户被禁用,请联系管理员!").build()));

        } else {

            response.getWriter().write(JSON.toJSONString(ResFailTemplate.builder().code(400).message("用户名或密码错误!").build()));

        }
    }
}

九、403无权限Handler

@Component
public class AuthenticationAccessDeniedHandler implements AccessDeniedHandler {

    @Override
    public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException)
            throws IOException, ServletException {
        response.setContentType("text/json;charset=utf-8");
        response.getWriter().write(JSON.toJSONString(ResFailTemplate.builder().code(403).message("权限不足!").build()));
    }
}

十、拦截Token 过滤器

@Slf4j
public class JWTAuthenticationFilter extends BasicAuthenticationFilter {

    @Autowired
    JWTUtil jwtUtil;

    private Integer tokenExpireTime;

    public JWTAuthenticationFilter(AuthenticationManager authenticationManager, Integer tokenExpireTime) {
        super(authenticationManager);
        this.tokenExpireTime = tokenExpireTime;
    }

    public JWTAuthenticationFilter(AuthenticationManager authenticationManager, AuthenticationEntryPoint authenticationEntryPoint) {
        super(authenticationManager, authenticationEntryPoint);
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {

        String token = request.getHeader("token");

        if (jwtUtil == null){
            jwtUtil = new JWTUtil();
        }

        boolean isold = jwtUtil.VerityToken(token);

        response.setContentType("text/json;charset=utf-8");

        if (!isold) {
            response.getWriter().write(JSON.toJSONString(ResFailTemplate.builder().code(401).message("登录失效!").build()));
            return;
        }

        String username = jwtUtil.getUserName(token);

        if (StringUtils.isEmpty(username)){
            response.getWriter().write(JSON.toJSONString(ResFailTemplate.builder().code(401).message("登录失效!").build()));
            return;
        }

        String role = jwtUtil.getUserRoles(token);
        List authorities = new ArrayList<>();

        if(StringUtils.isEmpty(role)){
            response.getWriter().write(JSON.toJSONString(ResFailTemplate.builder().code(403).message("权限不足!").build()));
            return;
        }
        authorities.add(new SimpleGrantedAuthority(role));

        User principal = new User();
        principal.setUsername(username);
        try {
            UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(principal, null, authorities);
            SecurityContextHolder.getContext().setAuthentication(authentication);
            String userid = jwtUtil.getUserid(token);

            request.setAttribute("userid",userid);
            request.setAttribute("username",username);
            request.setAttribute("role",role);
            System.out.println("过滤权限:"+role);
            chain.doFilter(request, response);
        }catch (Exception e){
            e.printStackTrace();
            response.getWriter().write(JSON.toJSONString(ResFailTemplate.builder().code(401).message("登录失效!").build()));
        }
    }
}

十一、配置SecurityConfig

@EnableGlobalMethodSecurity(prePostEnabled = true)

@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    UserService userService;

    @Autowired
    RoleService roleService;

    @Autowired
    AuthenticationSuccessHandler successHandler;

    @Autowired
    AuthenticationFailHandler failHandler;

    @Autowired
    AuthenticationAccessDeniedHandler deniedHandler;


    @Bean
    RoleHierarchy roleHierarchy() {
        RoleHierarchyImpl roleHierarchy = new RoleHierarchyImpl();
        String hierarchy = "ROLE_admin > ROLE_user > ROLE_common";
        roleHierarchy.setHierarchy(hierarchy);
        return roleHierarchy;
    }


    @Bean
    PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userService);
    }


    @Bean
    LoginAuthenticationFilter customAuthenticationFilter() throws Exception {
        LoginAuthenticationFilter filter = new LoginAuthenticationFilter();
        filter.setAuthenticationSuccessHandler(successHandler);
        filter.setAuthenticationFailureHandler(failHandler);
        filter.setFilterProcessesUrl("/login");
        //这句很关键,重用WebSecurityConfigurerAdapter配置的AuthenticationManager,不然要自己组装AuthenticationManager
        filter.setAuthenticationManager(authenticationManagerBean());
        return filter;
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        ExpressionUrlAuthorizationConfigurer.ExpressionInterceptUrlRegistry authorizeRequests = http
                .authorizeRequests();

        List menus = roleService.findMeun();
        for (Menu m:menus){
            System.out.println(m);
            String role = "";
            for (int i=0;i

十二、测试

@RestController
public class TestController {
    @Autowired
    UserService userService;
    @Autowired
    RoleService roleService;

    @GetMapping("/Admin/AdminTest")
    public String AdminTest(){
        return "Admin - Success";
    }

    @GetMapping("/User/UserTest")
    public String UserTest(){
        return "User - Success";
    }

    @GetMapping("/Common/CommonTest")
    public String CommonTest(HttpServletRequest request){
        String userid = (String) request.getAttribute("userid");
        String username = (String) request.getAttribute("username");
        String role = (String) request.getAttribute("role");

        return "Common - Success"+"userid="+userid+", username="+username+",role="+role;
    }
}

你可能感兴趣的:(SpringBoot,jwt)