基础开发框架搭建3---springbooot集成spring security实现登录及权限控制

基础开发框架搭建3—springbooot集成spring security实现登录及权限控制

spring security:

spring security是一个安全登录框架,常用于用户登录、注销、角色权限控制、页面接口访问控制等等,功能强大且上手较难,最近搭建基础开发框架简单集成一下。目前大多数教程都比较老旧,仍然使用了模板引擎、jsp相关的技术,这不符合我们目前的日常开发现状。这篇博客后端使用springboot2.x+mybatis,前端只使用了2个简单的html页面,比较易于理解security。

这篇博客想用spring security实现的比较简单的事情:
  • 用户登录和退出,即用户登录、退出的相关操作,当然包含session相关的操作,我不想自己做,我想让spring security帮我做。
  • 页面、restful接口的权限控制,我不想让非ADMIN的用户去访问到/admin/**相关的页面和接口,我想让spring security帮我拦截这些请求并返回权限不足/未登录登信息。
  • 当然spring security的功能远远不止这些,这边博客仅仅是简单集成,后面有机会会集成更多功能。
github地址:
https://github.com/hellozhaoxudong/springbootMerge

1.表结构和实体类

(1)相关表结构信息
  • 用户信息表sys_user
    基础开发框架搭建3---springbooot集成spring security实现登录及权限控制_第1张图片
  • 角色信息表sys_role
    注意下这里面的角色编码都要加上ROLE_前缀,因为security进行拦截后角色对比时会自动加上ROLE_前缀,此处若想深入研究请阅读源码。
    基础开发框架搭建3---springbooot集成spring security实现登录及权限控制_第2张图片
  • 用户-角色信息关联表sys_user_role
    基础开发框架搭建3---springbooot集成spring security实现登录及权限控制_第3张图片
(2)实体类

基础开发框架搭建3---springbooot集成spring security实现登录及权限控制_第4张图片

  • 用户信息实体
/**
 * @ClassName SysUser
 * @description 用户信息实体
 * @author [email protected]
 * @date 2019/4/28 15:50
 * @version 1.0
 * @since JDK 1.8
 */
@Table(name = "sys_user")
public class SysUser {
    /** 用户ID **/
    @Id
    private Long userId;

    /** 登录名 **/
    @Column
    private String username;

    /** 密码 **/
    @Column
    private String password;

    /** 用户真实姓名 **/
    @Column
    private String userRealName;

    /** 手机号 **/
    @Column
    private String phone;

    /** 邮箱 **/
    @Column
    private String email;

    /** 信用值 **/
    @Column
    private Long credit;

    /** getter & setter **/
}
  • 角色信息实体
/**
 * @ClassName SysRole
 * @description 角色信息实体
 * @author [email protected]
 * @date 2019/4/28 15:57
 * @version 1.0
 * @since JDK 1.8
 */
@Table(name = "sys_role")
public class SysRole {
    /** 角色ID **/
    @Id
    private Long roleId;

    /** 角色编码 **/
    @Column
    private String roleCode;

    /** 角色名称 **/
    @Column
    private String roleName;

    /** setter & getter **/
}
  • 用户-角色关联信息实体
/**
 * @ClassName SysUserRole
 * @description 用户角色实体
 * @author [email protected]
 * @date 2019/4/28 16:00
 * @version 1.0
 * @since JDK 1.8
 */
@Table(name = "sys_user_role")
public class SysUserRole {
    /** 用户角色信息ID **/
    @Id
    private Long userRoleId;

    /** 用户ID **/
    @Column
    private Long userId;

    /** 角色ID **/
    @Column
    private Long roleId;


    /** 角色编码 **/
    @Transient
    private String roleCode;

    /** 角色名称 **/
    @Transient
    private String roleName;
    
    /** setter & getter **/
}

2.根据用户名获取用户信息、根据用户ID获取用户角色信息两个逻辑代码

基础开发框架搭建3---springbooot集成spring security实现登录及权限控制_第5张图片

(1)根据用户名获取用户信息
  • SysUserService.java
/**
 * @ClassName SysUserService
 * @description 用户信息逻辑层
 * @author [email protected]
 * @date 2019/4/28 16:14
 * @version 1.0
 * @since JDK 1.8
 */
@Service
public class SysUserService {
    @Autowired
    private SysUserMapper mapper;

    /**
     * loadUserByUsername : 根据用户名查询用户信息
     *
     * @author [email protected]
     * @version 1.0
     * @date 2019/4/28 16:21
     * @return java.util.List
     * @since JDK 1.8
     */
    public SysUser loadUserByUsername(String username){
        SysUser queryUser = new SysUser();
        queryUser.setUsername(username);

        List sysUserList = mapper.select(queryUser);

        if(null == sysUserList || sysUserList.size() == 0){
            throw new BaseException("用户名不存在!");
        }else if(sysUserList.size() > 1){
            throw new BaseException("用户名存在冲突!");
        }

        return sysUserList.get(0);
    }
}
  • SysUserMapper.java
    这里继承了通用的Mapper插件tk.mybatis.mapper.common.Mapper,所以基础的增删改查不需要自己定义。集成通用插件的过程请参考该项目git中的代码注释。
/**
 * @ClassName SysUserMapper
 * @description 用户信息Mapper
 * @author [email protected]
 * @date 2019/4/28 16:14
 * @version 1.0
 * @since JDK 1.8
 */
public interface SysUserMapper extends Mapper, InsertListMapper {
}
(2)根据用户ID获取用户角色信息
  • SysUserRoleService.java
/**
 * @ClassName SysUserRoleService
 * @description 用户角色关联信息逻辑处理层
 * @author [email protected]
 * @date 2019/4/28 16:38
 * @version 1.0
 * @since JDK 1.8
 */
@Service
public class SysUserRoleService {
    @Autowired
    private SysUserRoleMapper mapper;

    /**
     * querySysUserRoleByUserId : 根据用户id查询角色信息
     *
     * @author [email protected]
     * @version 1.0
     * @date 2019/4/28 16:56
     * @return java.util.List
     * @since JDK 1.8
     */
    public List querySysUserRoleByUserId(Long userId){
        List list = mapper.querySysUserRoleByUserId(userId);
        if(null == list || list.size() < 1){
            throw new BaseException("用户下无任何角色!请联系开发者");
        }

        return list;
    }
}
  • SysUserRoleMapper.java
/**
 * @ClassName SysUserRoleMapper
 * @description 用户角色信息Mapper
 * @author [email protected]
 * @date 2019/4/28 16:36
 * @version 1.0
 * @since JDK 1.8
 */
public interface SysUserRoleMapper extends Mapper, InsertListMapper {

    /**
     * querySysUserRoleByUserId : 根据用户id查询角色信息
     *
     * @author [email protected]
     * @version 1.0
     * @date 2019/4/28 16:51
     * @return java.util.List
     * @since JDK 1.8
     */
    List querySysUserRoleByUserId(@Param("userId") Long userId);
}
  • SysUserRoleMapper.xml




    
        
        
        

        
        
    


    
    

3.spring security相关配置

基础开发框架搭建3---springbooot集成spring security实现登录及权限控制_第6张图片

(1)pom文件中引入依赖
		
        
            org.springframework.boot
            spring-boot-starter-security
        
(2)实现UserDetailsService

自己写一个类实现UserDetailsService,重写loadUserByUsername方法,作用就是我们自己去组装登录用户的用户名、密码、角色集信息并在配置类中注入给security。

@Service
public class UserDetailsServiceImpl implements UserDetailsService {
    @Autowired
    private SysUserService sysUserService;

    @Autowired
    private SysUserRoleService sysUserRoleService;

    /**
     * loadUserByUsername : 获取用户信息(用户名,密码,角色集)
     *
     * 返回UserDetails,这是一个接口,通常返回它的字类org.springframework.security.core.userdetails.User
     * User的构造需要三个参数:用户名,密码,角色集
     *
     * @author [email protected]
     * @version 1.0
     * @date 2019/4/29 14:36
     * @return org.springframework.security.core.userdetails.UserDetails
     * @since JDK 1.8
     */
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        // 用户信息
        SysUser sysUser = sysUserService.loadUserByUsername(username);

        // 角色信息
        List sysUserRoleList = sysUserRoleService.querySysUserRoleByUserId(sysUser.getUserId());

        List authorities = new ArrayList();
        SimpleGrantedAuthority simpleGrantedAuthority;
        for(SysUserRole sysUserRole : sysUserRoleList){
            simpleGrantedAuthority = new SimpleGrantedAuthority(sysUserRole.getRoleCode());
            authorities.add(simpleGrantedAuthority);
        }

        return new User(sysUser.getUsername(), sysUser.getPassword(), authorities);
    }
}
(3)spring security配置类
@Configuration  // 标识该类为配置类
@EnableWebSecurity  // 开启Spring Security服务
@EnableGlobalMethodSecurity(prePostEnabled = true)  // 开启全局Spring Security注解
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserDetailsServiceImpl userDetailsService;

    // 指定用户,角色信息加载及密码加密方式,将默认的userDetailsService替换成我们自己实现的UserDetailsServiceImpl
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService)
            .passwordEncoder(new PasswordEncoder() {
                @Override
                public String encode(CharSequence charSequence) {
                    return charSequence.toString();
                }

                @Override
                public boolean matches(CharSequence charSequence, String s) {
                    return s.equals(charSequence.toString());
                }
            });
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // 配置拦截规则
        http.authorizeRequests()
                .antMatchers("/login.html","/api/login", "/visitor/**").permitAll()	// "/login.html"是登录页面,"/api/login"是登录url,  "/visitor/**"游客访问相关的页面和接口所以我们直接不拦截
                .antMatchers("/admin/**").hasAnyRole("ADMIN")	// "/admin/ \*\*"相关的页面和接口,只能ADMIN角色访问。
                .anyRequest().authenticated();	// 其他所有的页面和请求登录成功后才可以访问

        // 配置登录相关信息
        http.formLogin()
                .loginPage("/login.html")   // 指定登录页面(当我们未登录状态访问一个页面时会自动跳转到此处指定的页面)
                .loginProcessingUrl("/api/login")   // 指定登录url(默认为/login,此处和表单的action要一致,即登录信息提交到此处指定的url后security才可进行登录处理)
                .usernameParameter("username")  // 指定登录用户名参数名称(默认为username)
                .passwordParameter("password")  // 指定密码参数名称(默认为password)
                .defaultSuccessUrl("/index.html")  // 指定登录成功后跳转页

                .failureUrl("/api/login/error") // 指定登录失败URL,可在该接口中抛出异常。(默认为/login?error,就是在controller中写一个接口,登录失败会跳转那个接口)
                .permitAll();

        // 配置注销相关信息
        http.logout()
                .logoutUrl("/api/loginout") // 指定注销URL(默认为/login,即需要注销时需要调用此处指定的url后security才可进行注销处理)
                .permitAll();

        // 关闭CSRF跨域
        http.csrf().disable();
    }

    // 配置对资源文件放行
    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/css/**", "/js/**");
    }
}

4.登录页面、主页

基础开发框架搭建3---springbooot集成spring security实现登录及权限控制_第7张图片

(1)登录页面login.html



    
    登陆


登陆

用户名:
密码:
(2)主页index.html



    
    欢迎


登陆成功

5.测试

需要测试:登录功能是否正常使用?html页面是否可以正确被拦截?接口是否可以正确被拦截?

(1)页面测试

基础开发框架搭建3---springbooot集成spring security实现登录及权限控制_第8张图片
admin/securitytest.html应该是只有角色为ADMIN的用户登录后才能访问。
visitor/securitytest.html无论登不登录都可以随意访问。

(2)URL测试

基础开发框架搭建3---springbooot集成spring security实现登录及权限控制_第9张图片

@RestController
@RequestMapping("/")
public class SecurityTestController {

    /**
     * baseTest : Spring Security 基础测试:未登录时访问该接口应该自动转到login.html,登录后访问该接口应返回“springsecurity”
     *
     * @author [email protected]
     * @version 1.0
     * @date 2019/5/6 15:02
     * @return java.lang.String
     * @since JDK 1.8
     */
    @GetMapping(value = "securitytest/basetest")
    public String baseTest(){
        return "spring security";
    }

    /**
     * adminSecurityTest :  API测试:未登录时访问该接口应该自动转到login.html,非管理员角色登录后应提示403权限不足,管理员登录后应返回“api测试:admin”
     *
     * @author [email protected]
     * @version 1.0
     * @date 2019/5/6 15:11
     * @return java.lang.String
     * @since JDK 1.8
     */
    @GetMapping(value = "admin/securitytest")
    public String adminSecurityTest(){
        return "api测试:admin";
    }
}

可以使用POSTMAN发送GET请求进行测试。
具体的测试可以在github下载该项目进行测试和使用,此处只放两张简单的图!
基础开发框架搭建3---springbooot集成spring security实现登录及权限控制_第10张图片
基础开发框架搭建3---springbooot集成spring security实现登录及权限控制_第11张图片

你可能感兴趣的:(JAVA)