跳至主要内容

Create a restful application with AngularJS and Grails(2): Secure the backend REST API


Secure the backend REST API

In Spring application, Spring Security is usually used to secure the application. Grails has a builtin Spring Security based plugin to integrate Spring Security into Grails applications.

Install SpringSecurity core plugin

Open BuildConfig.groovy file, add spring-security-core plugin.
plugins {
 ...
 compile ":spring-security-core:2.0-RC2"
}
Run the following command in the project root folder to initialize the spring security plugin.
grails compile --non-interactive --refresh-dependencies
And use the built-in s2-quickstart script from this plugin to create the essential domain classes.
grails s2-quickstart Person Authority Requestmap
When it is done, the basic security configuration is added in Config.groovy.
grails.plugin.springsecurity.userLookup.userDomainClassName = 'com.hantsylabs.grails.example.security.Person'
grails.plugin.springsecurity.userLookup.authorityJoinClassName = 'com.hantsylabs.grails.example.security.PersonAuthority'
grails.plugin.springsecurity.authority.className = 'com.hantsylabs.grails.example.security.Authority'
grails.plugin.springsecurity.requestMap.className = 'com.hantsylabs.grails.example.security.Requestmap'
grails.plugin.springsecurity.securityConfigType = 'Annotation'
grails.plugin.springsecurity.controllerAnnotations.staticRules = [
 '/':                              ['permitAll'],
 '/index':                         ['permitAll'],
 '/index.gsp':                     ['permitAll'],
 '/**/js/**':                      ['permitAll'],
 '/**/css/**':                     ['permitAll'],
 '/**/images/**':                  ['permitAll'],
 '/**/favicon.ico':                ['permitAll']
 ]

Configure securityConfigType

There are three securityConfigType supported by this spring security plugin.
  • Annotation
  • InterceptUrlMap
  • Requestmap
By default, the Annotation type is configured.
grails.plugin.springsecurity.controllerAnnotations.staticRules is use for configuring the protection rule for the static resources. It is a map, the key is the url, the value is the configuration attribute which is a list and can accept the Spring security constants or Spring expression, eg. IS_AUTHENTICATED, isFullyAuthenticated(). If you have some experience of Spring security before, it is easy to understatnd.
Besides these, in your Java codes, you can use Grails or Spring Security specific @Securedannotation on methods in a Controller to apply the security restrict rules.
If you select InterceptUrlMap, all resources are protected by url intercepting only.
grails.plugin.springsecurity.securityConfigType = 'InterceptUrlMap'
grails.plugin.springsecurity.interceptUrlMap  = [
 '/':                              ['permitAll'],
 '/index':                         ['permitAll'],
 '/index.gsp':                     ['permitAll'],
 '/**/js/**':                      ['permitAll'],
 '/**/css/**':                     ['permitAll'],
 '/**/images/**':                  ['permitAll'],
 '/**/favicon.ico':                ['permitAll']
 ]
For Requestmap, it is easy to understand, it store the url intercepting mapping rules into database.
grails.plugin.springsecurity.securityConfigType = 'Requestmap'
There is a Requestmap class already generated for this project.
class Requestmap {

 String url
 String configAttribute
 HttpMethod httpMethod

 static mapping = {
  cache true
 }

 static constraints = {
  url blank: false, unique: 'httpMethod'
  configAttribute blank: false
  httpMethod nullable: true
 }
}
In the BootStrap.groovy class, you can add some codes to initialize the Requestmap.
def init = { servletContext ->
 ...
  for (String url in [
   '/', '/index', '/index.gsp', '/**/favicon.ico',
   '/**/js/**', '/**/css/**', '/**/images/**',
   '/login', '/login.*', '/login/*',
   '/logout', '/logout.*', '/logout/*']) {
   new Requestmap(url: url, configAttribute: 'permitAll').save()
   }

}
In this sample, InterceptUrlMap is used as example.
grails.plugin.springsecurity.securityConfigType = 'InterceptUrlMap'
grails.plugin.springsecurity.interceptUrlMap  = [
 '/':                              ['permitAll'],
 '/index':                         ['permitAll'],
 '/index.gsp':                     ['permitAll'],
 '/**/js/**':                      ['permitAll'],
 '/**/css/**':                     ['permitAll'],
 '/**/images/**':                  ['permitAll'],
 '/**/favicon.ico':                ['permitAll'],
 '/login/**':                 ['permitAll'],
 '/logout/**':                 ['permitAll'],
 '/**':      ['isFullyAuthenticated()']
 ]
The security plugin provides a LoginController and LogoutController for login and logout actions.

Run the project

Open BootStrap.groovy file, add some sample user data for test purpose.
def init = { servletContext ->
  
 def person =new Person(username:"test", password:"test123")
 person.save()
  
 def roleUser=new Authority(authority:"ROLE_USER")
 roleUser.save()
  
 new PersonAuthority(person:person, authority:roleUser).save()
}
In Eclipse IDE(Spring ToolSuite), select Run as-> Grails Command(run-app) in the project context menu,
Or in the command line, run the following command in the project root folder to run the this project.
grails run-app
Try to access the protected REST API resources, for example,http://localhost:8080/angluarjs-grails-sample/books.json. It will redirect to a login page. Login as test/test123, it will show the protected resources.

Sample codes

评论

此博客中的热门博文

Build a Reactive application with Angular 5 and Spring Boot 2.0

I have created a post to describe Reactive programming supports in Spring 5 and its subprojects, all codes of this article are updated the latest Spring 5 RELEASE, check spring-reactive-sample under my Github account.
In this post, I will create a simple blog system, including:
A user can sign in and sign out.An authenticated user can create a post.An authenticated user can update a post.Only the user who has ADMIN role can delete a post.All users(including anonymous users) can view post list and post details.An authenticated user can add his comments to a certain post. The backend will be built with the latest Spring 5 reactive stack, including:
Spring Boot 2.0, at the moment the latest version is 2.0.0.M7Spring Data MongoDB supports reactive operations for MongoDBSpring Session adds reactive support for WebSessionSpring Security 5 aligns with Spring 5 reactive stack The frontend is an Angular based SPA and it will be generated by Angular CLI.
The source code is hosted on Github, …

Activating CDI in JSF 2.3

Activating CDI in JSF 2.3 When I upgraed my Java EE 7 sample to the newest Java EE 8, the first thing confused me is the CDI beans are not recoganized in Facelects template in a JSF 2.3 based web applicaiton, which is working in the development version, but in the final release version, they are always resolved as null. I filed an issue on Mojarra and discussed it with the developers from communities and the JSF experts.
According to the content of README, In a JSF 2.3 application, to activate CDI support, declaring a 2.3 versioned faces-config.xml and adding javax.faces.ENABLE_CDI_RESOLVER_CHAIN in web.xml is not enough, you have to declare @FacesConfig annotated class to enable CDI.
Here is the steps I created a workable JSF 2.3 applicatoin in Java EE 8.
Create a Java web application, this can be done easily by NetBeans IDE, or generated by Maven archetype, for exmaple.
$ mvn archetype:generate -DgroupId=com.example -DartifactId=demo -DarchetypeArtifactId=maven-archetype-w…

JSF 2.3:Websocket support

Websocket support One of the most attractive features is JSF 2.3 added native websocket support, it means you can write real-time applications with JSF and no need extra effort.
To enable websocket support, you have to add javax.faces.ENABLE_WEBSOCKET_ENDPOINT in web.xml.
<context-param> <param-name>javax.faces.ENABLE_WEBSOCKET_ENDPOINT</param-name> <param-value>true</param-value> </context-param> Hello Websocket Let's start with a simple example.
@ViewScoped@Named("helloBean") publicclassHelloBeanimplementsSerializable { privatestaticfinalLoggerLOG=Logger.getLogger(HelloBean.class.getName()); @Inject@PushPushContext helloChannel; String message; publicvoidsendMessage() { LOG.log(Level.INFO, "send push message"); this.sendPushMessage("hello"); } privatevoidsendPushMessage(Objectmessage) { helloChannel.send(""+ message +" at &…