zoukankan      html  css  js  c++  java
  • springboot-28-security(一)用户角色控制

    spring security 使用众多的拦截器实现权限控制的, 其核心有2个重要的概念: 认证(Authentication) 和授权 (Authorization)), 认证就是确认用户可以访问当前系统, 授权即确定用户有相应的权限, 

        现在先大概过一遍整个流程,用户登陆,会被AuthenticationProcessingFilter拦截,调用AuthenticationManager的实现,而且AuthenticationManager会调用ProviderManager来获取用户验证信息(不同的Provider调用的服务不同,因为这些信息可以是在数据库上,可以是在LDAP服务器上,可以是xml配置文件上等),如果验证通过后会将用户的权限信息封装一个User放到spring的全局缓存SecurityContextHolder中,以备后面访问资源时使用。
    访问资源(即授权管理),访问url时,会通过AbstractSecurityInterceptor拦截器拦截,其中会调用FilterInvocationSecurityMetadataSource的方法来获取被拦截url所需的全部权限,在调用授权管理器AccessDecisionManager,这个授权管理器会通过spring的全局缓存SecurityContextHolder获取用户的权限信息,还会获取被拦截的url和被拦截url所需的全部权限,然后根据所配的策略(有:一票决定,一票否定,少数服从多数等),如果权限足够,则返回,权限不够则报错并调用权限不足页面 ( http://blog.csdn.net/u012367513/article/details/38866465)
     
      本例的用户和角色信息存储在mysql, 使用mybatis进行查询: http://www.cnblogs.com/wenbronk/p/7357996.html

     项目 使用 idea + gradle

    dependencies {
        compile("org.springframework.boot:spring-boot-devtools")
        compile("org.springframework.boot:spring-boot-starter")
        compile("org.springframework.boot:spring-boot-starter-web")
        compile("org.springframework.boot:spring-boot-starter-log4j2")
        compile("com.fasterxml.jackson.dataformat:jackson-dataformat-yaml")
        compile("org.codehaus.groovy:groovy-all:2.4.12")
    
        compile("org.springframework.boot:spring-boot-starter-security")
        compile("org.springframework.boot:spring-boot-starter-thymeleaf")
        compile("org.thymeleaf.extras:thymeleaf-extras-springsecurity4")
    
        compile ("mysql:mysql-connector-java")
        compile 'com.alibaba:druid-spring-boot-starter:1.1.2'
        compile ("org.mybatis.spring.boot:mybatis-spring-boot-starter:1.1.1")
    
        compile 'com.alibaba:fastjson:1.1.15'
        compile 'javax.inject:javax.inject:1'
        testCompile group: 'junit', name: 'junit', version: '4.12'
        testCompile("org.springframework.boot:spring-boot-starter-test")
    
    }

    1, 导入基础数据, 调试mybatis

    1) , 建表

    /*
    Navicat MySQL Data Transfer
    Source Server         : 本地
    Source Host           : localhost:3306
    Source Database       : test
    Target Server Type    : MYSQL
    Date: 2017-8-14 22:17:33
    */
    
    SET FOREIGN_KEY_CHECKS=0;
    
    -- ----------------------------
    -- Table structure for `sys_user`
    -- ----------------------------
    DROP TABLE IF EXISTS `sys_user`;
    CREATE TABLE `sys_user` (
      `id` INT (32) NOT NULL AUTO_INCREMENT COMMENT '主键id',
      `username` varchar(32) DEFAULT NULL COMMENT '用户名',
      `password` varchar(32) DEFAULT NULL COMMENT '密码',
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=28 DEFAULT CHARSET=utf8;
    
    -- ----------------------------
    -- Table structure for `sys_role`
    -- ----------------------------
    DROP TABLE IF EXISTS `sys_role`;
    CREATE TABLE `sys_role` (
      `id` INT (32) NOT NULL AUTO_INCREMENT COMMENT '主键id',
      `name` varchar(32) DEFAULT NULL COMMENT '用户名',
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=28 DEFAULT CHARSET=utf8;
    -- ----------------------------
    -- Table structure for `sys_role_user`
    -- ----------------------------
    DROP TABLE IF EXISTS `sys_role_user`;
    CREATE TABLE `sys_role_user` (
      `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键id',
      `sys_user_id` INT(32) NOT NULL COMMENT 'user_id',
      `sys_role_id` INT(32) NOT NULL COMMENT 'role_id',
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=28 DEFAULT CHARSET=utf8;
    
    ALTER TABLE sys_role_user ADD CONSTRAINT sys_FK1 FOREIGN KEY(sys_user_id) REFERENCES sys_user(id);
    ALTER TABLE sys_role_user ADD CONSTRAINT role_FK2 FOREIGN KEY(sys_role_id) REFERENCES sys_role(id);

    导入数据

    insert into SYS_USER (id,username, password) values (1,'vini', '123');
    insert into SYS_USER (id,username, password) values (2,'bronk', '123');
    
    insert into SYS_ROLE(id,name) values(1,'ROLE_ADMIN');
    insert into SYS_ROLE(id,name) values(2,'ROLE_USER');
    
    insert into SYS_ROLE_USER(SYS_USER_ID,sys_role_id) values(1,1);
    insert into SYS_ROLE_USER(SYS_USER_ID,sys_role_id) values(2,2);

    在 application.yml中配置如下, 可以在启动程序时自动执行

    spring: 
      datasource:
        url: jdbc:mysql://localhost:3306/springboot
        username: root
        password: root
    #    type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.jdbc.Driver
      # 一下2行 schema: classpath:security.sql data: classpath:security
    -data.sql

    2), mapper映射

    package com.wenbronk.security.mapper
    
    import com.wenbronk.security.entity.SysUser
    
    /**
     * Created by wenbronk on 2017/8/14.
     */
    interface SysUserMapper {
        SysUser findByUserName(String username)
    }

    在 resources/mybatis/mapper中添加: 

    <?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="com.wenbronk.security.mapper.SysUserMapper">
    
        <resultMap id="sys_user_map" type="SysUser">
            <id property="id" column="id" />
            <result property="username" column="username" />
            <result property="password" column="password" />
            <collection property="roles" ofType="SysRole">
                <result column="name" property="name" />
            </collection>
    
        </resultMap>
    
        <select id="findByUserName" parameterType="string" resultMap="sys_user_map">
            select u.id, u.username, u.password, r.name
            from sys_user u
            LEFT JOIN sys_role_user s on u.id = s.sys_user_id
            LEFT JOIN sys_role r on r.id = s.sys_role_id
            WHERE username = #{username}
        </select>
    </mapper>

    在application.yml中配置

    mybatis:
      config-location: classpath:mybatis/SqlMapConfig.xml
      mapper-locations: classpath:mybatis/mapper/*.xml

    在main方法上添加mapper扫描: 

    @SpringBootApplication
    @MapperScan("com.wenbronk.security.mapper")
    public class SecurityApplication {
        public static void main(String[] args) {
            SpringApplication.run(SecurityApplication.class);
        }
    }

     3), 实体类

    class Msg {
        String title
        String content
        String etraInfo
    
        Msg() {
        }
    
        Msg(String title, String content, String etraInfo) {
            this.title = title
            this.content = content
            this.etraInfo = etraInfo
        }
    }

    SysUser.groovy

    package com.wenbronk.security.entity
    
    /**
     * Created by wenbronk on 2017/8/14.
     */
    class SysUser {
        int id
        def username
        def password
        List<SysRole> roles
    
        @Override
        public String toString() {
            return "SysUser{" +
                    "id=" + id +
                    ", username=" + username +
                    ", password=" + password +
                    ", roles=" + roles +
                    '}';
        }
    }

    SysRole.groovy

    package com.wenbronk.security.entity
    
    /**
     * Created by wenbronk on 2017/8/14.
     */
    class SysUser {
        int id
        def username
        def password
        List<SysRole> roles
    
        @Override
        public String toString() {
            return "SysUser{" +
                    "id=" + id +
                    ", username=" + username +
                    ", password=" + password +
                    ", roles=" + roles +
                    '}';
        }
    }

    4) , 测试mybatis

        @Test
        void test2() {
            def name = sysUserMapper.findByUserName('vini')
            println name
        }

    2, security相关配置

    1), CustomerUserService.groovy
    package com.wenbronk.security.security.service
    
    import com.wenbronk.security.entity.SysRole
    import com.wenbronk.security.entity.SysUser
    import com.wenbronk.security.mapper.SysUserMapper
    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 javax.inject.Inject
    /**
     * Created by wenbronk on 2017/8/15.
     */
    @Service
    class CustomUserService implements UserDetailsService {
    
        @Inject
        SysUserMapper sysUserMapper;
    
        @Override
        UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
            def sysUser = sysUserMapper.findByUserName(s) as SysUser
            assert sysUser != null
            List<SimpleGrantedAuthority> authorities = new ArrayList<>()
            for(SysRole role : sysUser.getRoles()) {
                authorities.add(new SimpleGrantedAuthority(role.getName()))
                println role.getName();
            }
            return new User(sysUser.getUsername(), sysUser.getPassword(), authorities)
        }
    }

    2), WebSecurityConfig.groovy

    package com.wenbronk.security.security.config
    
    import com.wenbronk.security.security.service.CustomUserService
    import org.springframework.context.annotation.Configuration
    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 javax.inject.Inject
    /**
     * Created by wenbronk on 2017/8/15.
     */
    @Configuration
    @EnableWebSecurity
    class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    
        @Inject
        CustomUserService customUserService;
    
        @Override
        protected void configure(AuthenticationManagerBuilder auth) throws Exception {
            auth.userDetailsService(customUserService);
        }
    
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.authorizeRequests()
                .anyRequest().authenticated()   // 任何请求都拦截
                .and()
                .formLogin()
                .loginPage("/login")
                .failureUrl("/login?error")
                .permitAll()        // 登陆后可访问任意页面
                .and()
                .logout().permitAll();  // 注销后任意访问
    
        }
    }

    3, 页面

    1), 页面转向设置

    package com.wenbronk.security.config
    
    import org.springframework.context.annotation.Configuration
    import org.springframework.web.servlet.config.annotation.ViewControllerRegistry
    import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter
    /**
     * Created by wenbronk on 2017/8/15.
     */
    @Configuration
    class WebMvcConfig extends WebMvcConfigurerAdapter{
    
        @Override
        void addViewControllers(ViewControllerRegistry registry) {
            registry.addViewController("/login").setViewName("login")
        }
    }

     controller.groovy

    package com.wenbronk.security.controller
    
    import com.wenbronk.security.entity.Msg
    import org.springframework.stereotype.Controller
    import org.springframework.ui.Model
    import org.springframework.web.bind.annotation.RequestMapping
    /**
     * Created by wenbronk on 2017/8/14.
     */
    @Controller
    class SecurityController {
    
        @RequestMapping("/")
        def index(Model model) {
            def msg = new Msg("测试标题", "测试内容", "额外信息, 只对管理员显示")
            model.addAttribute("msg", msg);
            "home"
        }
        
    }

    在resources下放入静态资源, bootstramp.min.css, 以及thymeleaf页面

    login.html

    <!DOCTYPE html>
    <html xmlns:th="http://www.thymeleaf.org">
    <head>
        <meta content="text/html;charset=UTF-8"/>
        <title>登录页面</title>
        <link rel="stylesheet" th:href="@{css/bootstrap.min.css}"/>
        <style type="text/css">
            body {
                padding-top: 50px;
            }
            .starter-template {
                padding: 40px 15px;
                text-align: center;
            }
        </style>
    </head>
    <body>
    
    <nav class="navbar navbar-inverse navbar-fixed-top">
        <div class="container">
            <div class="navbar-header">
                <a class="navbar-brand" href="#">Spring Security演示</a>
            </div>
            <div id="navbar" class="collapse navbar-collapse">
                <ul class="nav navbar-nav">
                    <li><a th:href="@{/}"> 首页 </a></li>
    
                </ul>
            </div><!--/.nav-collapse -->
        </div>
    </nav>
    <div class="container">
    
        <div class="starter-template">
            <p th:if="${param.logout}" class="bg-warning">已成功注销</p><!-- 1 -->
            <p th:if="${param.error}" class="bg-danger">有错误,请重试</p> <!-- 2 -->
            <h2>使用账号密码登录</h2>
            <form name="form" th:action="@{/login}" action="/login" method="POST"> <!-- 3 -->
                <div class="form-group">
                    <label for="username">账号</label>
                    <input type="text" class="form-control" name="username" value="" placeholder="账号" />
                </div>
                <div class="form-group">
                    <label for="password">密码</label>
                    <input type="password" class="form-control" name="password" placeholder="密码" />
                </div>
                <input type="submit" id="login" value="Login" class="btn btn-primary" />
            </form>
        </div>
    </div>
    </body>
    </html>

    home.html

    <!DOCTYPE html>
    <html xmlns:th="http://www.thymeleaf.org"
          xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity4">
    <head>
    <meta content="text/html;charset=UTF-8"/>
    <title sec:authentication="name"></title>
    <link rel="stylesheet" th:href="@{css/bootstrap.min.css}" />
    <style type="text/css">
    body {
      padding-top: 50px;
    }
    .starter-template {
      padding: 40px 15px;
      text-align: center;
    }
    </style>
    </head>
    <body>
         <nav class="navbar navbar-inverse navbar-fixed-top">
          <div class="container">
            <div class="navbar-header">
              <a class="navbar-brand" href="#">Spring Security演示</a>
            </div>
            <div id="navbar" class="collapse navbar-collapse">
              <ul class="nav navbar-nav">
               <li><a th:href="@{/}"> 首页 </a></li>
              </ul>
            </div><!--/.nav-collapse -->
          </div>
        </nav>
    
    
         <div class="container">
    
          <div class="starter-template">
              <h1 th:text="${msg.title}"></h1>
    
            <p class="bg-primary" th:text="${msg.content}"></p>
    
            <div sec:authorize="hasRole('ROLE_ADMIN')"> <!-- 用户类型为ROLE_ADMIN 显示 -->
                 <p class="bg-info" th:text="${msg.etraInfo}"></p>
            </div>
    
            <div sec:authorize="hasRole('ROLE_USER')"> <!-- 用户类型为 ROLE_USER 显示 -->
                 <p class="bg-info">无更多信息显示</p>
            </div>
    
            <form th:action="@{/logout}" method="post">
                <input type="submit" class="btn btn-primary" value="注销"/>
            </form>
          </div>
    
        </div>
    </body>
    
    
    </html>
     
     参见: JavaEE颠覆者, springboot实战
      
  • 相关阅读:
    myfocus之焦点图
    win7磁盘分区工具
    java线程两种创建方式的区别与模拟买票情景
    jsp指令与动作
    Cookie记住登陆账号和密码
    jsp+javabean实现简单的用户登陆
    jsp简单登陆实现
    strut2 文件上传完整案例
    poi 导出excel文件
    poi excel文件的导入
  • 原文地址:https://www.cnblogs.com/wenbronk/p/7379865.html
Copyright © 2011-2022 走看看