zoukankan      html  css  js  c++  java
  • Grails

    Grails SDK

    下载SDK,配置环境变量GRAILS_HOME和PATH
    grails-4.0.3.zip

    Create APP

    grails create-app cn.duchaoqun.demo
    cd demo
    run-app

    Install Grails Spring Security Core Plugin

    • 在build中添加引用
    compile "org.grails.plugins:spring-security-core:4.0.0.RC2"
    stop-app
    compile

    Create User, Role, and Product Domain Class

    • 在添加完插件之后,就可以创建如下命令创建 Domain 了。
    s2-quickstart cn.duchaoqun User Role
    • 修改grails-app/domain/cn/duchaoqun/Role.groovy
    String toString() {
      authority
    }
    • 修改grails-app/domain/cn/duchaoqun/User.groovy
    // 在password字段后面添加
    String fullname
    // 添加约束
    static constraints = {
        password nullable: false, blank: false, password: true
        username nullable: false, blank: false, unique: true
        fullname nullable: false, blank: false
    }
    • 创建 Product实体 grails-app/domain/cn/duchaoqun/Product.groovy
    create-domain-class cn.duchaoqun.Product
    
    package cn.duchaoqun
    
    class Product {
    
        String prodCode
        String prodName
        String prodModel
        String prodDesc
        String prodImageUrl
        String prodPrice
    
        static constraints = {
            prodCode nullable: false, blank: false
            prodName nullable: false, blank: false
            prodModel nullable: false, blank: false
            prodDesc nullable: false, blank: false
            prodImageUrl nullable: true
            prodPrice nullable: false, blank: false
        }
    
        String toString() {
            prodName
        }
    }

    Create CustomUserDetailsService

    • 因为我们修改了User实体,这里我们需要自定义一个CustomUserDetails,创建src/main/groovy/cn/duchaoqun/CustomUserDetails.groovy
    package cn.duchaoqun
    
    import grails.plugin.springsecurity.userdetails.GrailsUser
    import org.springframework.security.core.GrantedAuthority
    
    class CustomUserDetails extends GrailsUser {
    
       final String fullname
    
       CustomUserDetails(String username, String password, boolean enabled,
                     boolean accountNonExpired, boolean credentialsNonExpired,
                     boolean accountNonLocked,
                     Collection<GrantedAuthority> authorities,
                     long id, String fullname) {
          super(username, password, enabled, accountNonExpired,
                credentialsNonExpired, accountNonLocked, authorities, id)
    
          this.fullname = fullname
       }
    }
    • 创建一个新的 Service
    create-service cn.duchaoqun.CustomUserDetails
    package cn.duchaoqun
    
    import grails.plugin.springsecurity.SpringSecurityUtils
    import grails.plugin.springsecurity.userdetails.GrailsUserDetailsService
    import grails.plugin.springsecurity.userdetails.NoStackUsernameNotFoundException
    import grails.gorm.transactions.Transactional
    import org.springframework.security.core.authority.SimpleGrantedAuthority
    import org.springframework.security.core.userdetails.UserDetails
    import org.springframework.security.core.userdetails.UsernameNotFoundException
    
    class CustomUserDetailsService implements GrailsUserDetailsService {
    
       /**
        * Some Spring Security classes (e.g. RoleHierarchyVoter) expect at least
        * one role, so we give a user with no granted roles this one which gets
        * past that restriction but doesn't grant anything.
        */
       static final List NO_ROLES = [new SimpleGrantedAuthority(SpringSecurityUtils.NO_ROLE)]
    
       UserDetails loadUserByUsername(String username, boolean loadRoles)
             throws UsernameNotFoundException {
          return loadUserByUsername(username)
       }
    
       @Transactional(readOnly=true, noRollbackFor=[IllegalArgumentException, UsernameNotFoundException])
       UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
    
          User user = User.findByUsername(username)
          if (!user) throw new NoStackUsernameNotFoundException()
    
          def roles = user.authorities
    
          // or if you are using role groups:
          // def roles = user.authorities.collect { it.authorities }.flatten().unique()
    
          def authorities = roles.collect {
             new SimpleGrantedAuthority(it.authority)
          }
    
          return new CustomUserDetails(user.username, user.password, user.enabled,
                !user.accountExpired, !user.passwordExpired,
                !user.accountLocked, authorities ?: NO_ROLES, user.id,
                user.fullname)
       }
    }
    • 然后再 grails-app/conf/spring/resources.groovy 中注册新的 Service
    import cn.duchaoqun.UserPasswordEncoderListener
    import cn.duchaoqun.CustomUserDetailsService
    // Place your Spring DSL code here
    beans = {
        userPasswordEncoderListener(UserPasswordEncoderListener)
        userDetailsService(CustomUserDetailsService)
    }

    Override Login Auth View

    • 自定义登录页面。
    • 在 views 文件夹创建一个login 文件夹,然后再里面创建 auth.gsp
    grails-app/views/login/auth.gsp
    
    <html>
    <head>
        <meta name="layout" content="${gspLayout ?: 'main'}"/>
        <title><g:message code='springSecurity.login.title'/></title>
    </head>
    
    <body>
        <div class="row">
          <div class="col-sm-9 col-md-7 col-lg-5 mx-auto">
            <div class="card card-signin my-5">
              <div class="card-body">
                <h5 class="card-title text-center">Please Login</h5>
                <g:if test='${flash.message}'>
                    <div class="alert alert-danger" role="alert">${flash.message}</div>
                </g:if>
                <form class="form-signin" action="${postUrl ?: '/login/authenticate'}" method="POST" id="loginForm" autocomplete="off">
                  <div class="form-group">
                      <label for="username">Username</label>
                    <input type="text" class="form-control" name="${usernameParameter ?: 'username'}" id="username" autocapitalize="none"/>
                  </div>
    
                  <div class="form-group">
                      <label for="password">Password</label>
                    <input type="password" class="form-control" name="${passwordParameter ?: 'password'}" id="password"/>
                    <i id="passwordToggler" title="toggle password display" onclick="passwordDisplayToggle()">&#128065;</i>
                  </div>
    
                  <div class="form-group form-check">
                      <label class="form-check-label">
                          <input type="checkbox" class="form-check-input" name="${rememberMeParameter ?: 'remember-me'}" id="remember_me" <g:if test='${hasCookie}'>checked="checked"</g:if>/> Remember me
                    </label>
                  </div>
                  <button id="submit" class="btn btn-lg btn-primary btn-block text-uppercase" type="submit">Sign in</button>
                  <hr class="my-4">
                  <p>Don't have an account? <g:link controller="register">Register</g:link></p>
                </form>
              </div>
            </div>
          </div>
        </div>
        <script type="text/javascript">
            document.addEventListener("DOMContentLoaded", function(event) {
                document.forms['loginForm'].elements['username'].focus();
            });
            function passwordDisplayToggle() {
                var toggleEl = document.getElementById("passwordToggler");
                var eyeIcon = 'u{1F441}';
                var xIcon = 'u{2715}';
                var passEl = document.getElementById("password");
                if (passEl.type === "password") {
                    toggleEl.innerHTML = xIcon;
                    passEl.type = "text";
                } else {
                    toggleEl.innerHTML = eyeIcon;
                    passEl.type = "password";
                }
            }
        </script>
    </body>
    </html>
    • 将改页面设置为默认页面grails-app/controllers/UrlMappings.groovy
    // 修改前
    "/"(view: "index")
    // 修改后
    "/"(controller:'login', action:'auth')

    Add User Info and Logout to the Navbar

    • 修改grails-app/views/layout/main.gsp
    <!doctype html>
    <html lang="en" class="no-js">
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
        <meta http-equiv="X-UA-Compatible" content="IE=edge"/>
        <title>
            <g:layoutTitle default="Grails"/>
        </title>
        <meta name="viewport" content="width=device-width, initial-scale=1"/>
        <asset:link rel="icon" href="favicon.ico" type="image/x-ico"/>
    
        <asset:stylesheet src="application.css"/>
    
        <g:layoutHead/>
    </head>
    
    <body>
    
    <nav class="navbar navbar-expand-lg navbar-dark navbar-static-top" role="navigation">
        <a class="navbar-brand" href="/#"><asset:image src="grails.svg" alt="Grails Logo"/></a>
        <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarContent" aria-controls="navbarContent" aria-expanded="false" aria-label="Toggle navigation">
            <span class="navbar-toggler-icon"></span>
        </button>
    
        <div class="collapse navbar-collapse" aria-expanded="false" style="height: 0.8px;" id="navbarContent">
            <ul class="nav navbar-nav ml-auto">
                <g:pageProperty name="page.nav"/>
                <sec:ifLoggedIn>
                  <li class="nav-item dropdown">
                      <a class="nav-link dropdown-toggle" href="#" id="navbardrop" data-toggle="dropdown">
                        <sec:loggedInUserInfo field='fullname'/>
                      </a>
                      <div class="dropdown-menu navbar-dark">
                        <g:form controller="logout">
                          <g:submitButton class="dropdown-item navbar-dark color-light" name="Submit" value="Logout" style="color:gray" />
                        </g:form>
                      </div>
                  </li>
                </sec:ifLoggedIn>
            </ul>
        </div>
    
    </nav>
    
    <div class="container">
        <g:layoutBody/>
    </div>
    
    <div class="footer row" role="contentinfo">
        <div class="col">
            <a href="http://guides.grails.org" target="_blank">
                <asset:image src="advancedgrails.svg" alt="Grails Guides" class="float-left"/>
            </a>
            <strong class="centered"><a href="http://guides.grails.org" target="_blank">Grails Guides</a></strong>
            <p>Building your first Grails app? Looking to add security, or create a Single-Page-App? Check out the <a href="http://guides.grails.org" target="_blank">Grails Guides</a> for step-by-step tutorials.</p>
    
        </div>
        <div class="col">
            <a href="http://docs.grails.org" target="_blank">
                <asset:image src="documentation.svg" alt="Grails Documentation" class="float-left"/>
            </a>
            <strong class="centered"><a href="http://docs.grails.org" target="_blank">Documentation</a></strong>
            <p>Ready to dig in? You can find in-depth documentation for all the features of Grails in the <a href="http://docs.grails.org" target="_blank">User Guide</a>.</p>
    
        </div>
    
        <div class="col">
            <a href="https://grails-slack.cfapps.io" target="_blank">
                <asset:image src="slack.svg" alt="Grails Slack" class="float-left"/>
            </a>
            <strong class="centered"><a href="https://grails-slack.cfapps.io" target="_blank">Join the Community</a></strong>
            <p>Get feedback and share your experience with other Grails developers in the community <a href="https://grails-slack.cfapps.io" target="_blank">Slack channel</a>.</p>
        </div>
    </div>
    
    <div id="spinner" class="spinner" style="display:none;">
        <g:message code="spinner.alt" default="Loading&hellip;"/>
    </div>
    
    <asset:javascript src="application.js"/>
    
    </body>
    </html>

    Create Register Controller and View

    • 创建register控制器
    create-controller cn.duchaoqun.Register
    • 填充代码
    package cn.duchaoqun.
    
    import grails.validation.ValidationException
    import grails.gorm.transactions.Transactional
    import grails.plugin.springsecurity.annotation.Secured
    import cn.duchaoqun.User
    import cn.duchaoqun.Role
    import cn.duchaoqun.UserRole
    
    @Transactional
    @Secured('permitAll')
    class RegisterController {
    
        static allowedMethods = [register: "POST"]
    
        def index() { }
    
        def register() {
            if(!params.password.equals(params.repassword)) {
                flash.message = "Password and Re-Password not match"
                redirect action: "index"
                return
            } else {
                try {
                    def user = User.findByUsername(params.username)?: new User(username: params.username, password: params.password, fullname: params.fullname).save()
                    def role = Role.get(params.role.id)
                    if(user && role) {
                        UserRole.create user, role
    
                        UserRole.withSession {
                          it.flush()
                          it.clear()
                        }
    
                        flash.message = "You have registered successfully. Please login."
                        redirect controller: "login", action: "auth"
                    } else {
                        flash.message = "Register failed"
                        render view: "index"
                        return
                    }
                } catch (ValidationException e) {
                    flash.message = "Register Failed"
                    redirect action: "index"
                    return
                }
            }
        }
    }
    • 创建 Register 页面 grails-app/views/register/index.gsp
    <html>
    <head>
        <meta name="layout" content="${gspLayout ?: 'main'}"/>
        <title>Register</title>
    </head>
    
    <body>
        <div class="row">
        <div class="col-sm-9 col-md-7 col-lg-5 mx-auto">
          <div class="card card-signin my-5">
            <div class="card-body">
              <h5 class="card-title text-center">Register Here</h5>
                        <g:if test='${flash.message}'>
                            <div class="alert alert-danger" role="alert">${flash.message}</div>
                        </g:if>
                  <form class="form-signin" action="register" method="POST" id="loginForm" autocomplete="off">
                          <div class="form-group">
                              <label for="role">Role</label>
                  <g:select class="form-control" name="role.id"
                        from="${cn.duchaoqun.Role.list()}"
                        optionKey="id" />
                    </div>
    
                <div class="form-group">
                        <label for="username">Username</label>
                  <input type="text" placeholder="Your username" class="form-control" name="username" id="username" autocapitalize="none"/>
                </div>
    
                <div class="form-group">
                              <label for="password">Password</label>
                  <input type="password" placeholder="Your password" class="form-control" name="password" id="password"/>
                </div>
    
                <div class="form-group">
                              <label for="password">Re-Enter Password</label>
                  <input type="password" placeholder="Re-enter password" class="form-control" name="repassword" id="repassword"/>
                </div>
    
                          <div class="form-group">
                              <label for="username">Full Name</label>
                  <input type="text" placeholder="Your full name" class="form-control" name="fullname" id="fullname" autocapitalize="none"/>
                </div>
    
                <button id="submit" class="btn btn-lg btn-primary btn-block text-uppercase" type="submit">Register</button>
                <hr class="my-4">
                <p>Already have an account? <g:link controller="login" action="auth">Login</g:link></p>
              </form>
            </div>
          </div>
        </div>
      </div>
        <script type="text/javascript">
            document.addEventListener("DOMContentLoaded", function(event) {
                document.forms['loginForm'].elements['username'].focus();
            });
        </script>
    </body>
    </html>

    Create the Secure Product CRUD Scaffolding

    • 创建一个实体
    generate-all cn.duchaoqun.Product
    • 修改对应的 Controller,grails-app/controllers/ProductController.groovy
    package cn.duchaoqun
    
    import grails.validation.ValidationException
    import static org.springframework.http.HttpStatus.*
    import grails.plugin.springsecurity.annotation.Secured
    
    class ProductController {
    
        ProductService productService
    
        static allowedMethods = [save: "POST", update: "PUT", delete: "DELETE"]
    
        @Secured(['ROLE_ADMIN', 'ROLE_USER'])
        def index(Integer max) {
            params.max = Math.min(max ?: 10, 100)
            respond productService.list(params), model:[productCount: productService.count()]
        }
    
        @Secured(['ROLE_ADMIN', 'ROLE_USER'])
        def show(Long id) {
            respond productService.get(id)
        }
    
        @Secured('ROLE_ADMIN')
        def create() {
            respond new Product(params)
        }
    
        @Secured('ROLE_ADMIN')
        def save(Product product) {
            if (product == null) {
                notFound()
                return
            }
    
            try {
                productService.save(product)
            } catch (ValidationException e) {
                respond product.errors, view:'create'
                return
            }
    
            request.withFormat {
                form multipartForm {
                    flash.message = message(code: 'default.created.message', args: [message(code: 'product.label', default: 'Product'), product.id])
                    redirect product
                }
                '*' { respond product, [status: CREATED] }
            }
        }
    
        @Secured('ROLE_ADMIN')
        def edit(Long id) {
            respond productService.get(id)
        }
    
        @Secured('ROLE_ADMIN')
        def update(Product product) {
            if (product == null) {
                notFound()
                return
            }
    
            try {
                productService.save(product)
            } catch (ValidationException e) {
                respond product.errors, view:'edit'
                return
            }
    
            request.withFormat {
                form multipartForm {
                    flash.message = message(code: 'default.updated.message', args: [message(code: 'product.label', default: 'Product'), product.id])
                    redirect product
                }
                '*'{ respond product, [status: OK] }
            }
        }
    
        @Secured('ROLE_ADMIN')
        def delete(Long id) {
            if (id == null) {
                notFound()
                return
            }
    
            productService.delete(id)
    
            request.withFormat {
                form multipartForm {
                    flash.message = message(code: 'default.deleted.message', args: [message(code: 'product.label', default: 'Product'), id])
                    redirect action:"index", method:"GET"
                }
                '*'{ render status: NO_CONTENT }
            }
        }
    
        protected void notFound() {
            request.withFormat {
                form multipartForm {
                    flash.message = message(code: 'default.not.found.message', args: [message(code: 'product.label', default: 'Product'), params.id])
                    redirect action: "index", method: "GET"
                }
                '*'{ render status: NOT_FOUND }
            }
        }
    }
    • 设置登录成功后的默认页面 grails-app/conf/application.groovy
    grails.plugin.springsecurity.successHandler.defaultTargetUrl = '/product'
  • 相关阅读:
    Visio使用遇到的问题
    UML类图符号 各种关系说明以及举例
    测试人员与开发人员之间的关系如何?
    linux命令学习-复制(cp,scp)
    linux服务器报Too many open files的解决方法
    QTP学习一添加默认的注释及调用外部vbs文件
    关于JAVA应用中文字体显示小方框的问题解决
    web测试方法总结
    linux命令学习-su
    Oracle定义varchar2()类型存储汉字的长度问题
  • 原文地址:https://www.cnblogs.com/duchaoqun/p/12875927.html
Copyright © 2011-2022 走看看