diff --git a/apache-shiro/pom.xml b/apache-shiro/pom.xml
index 97ed872a26..711ddb5cee 100644
--- a/apache-shiro/pom.xml
+++ b/apache-shiro/pom.xml
@@ -9,9 +9,9 @@
1.0-SNAPSHOT
- com.baeldung
- parent-modules
- 1.0.0-SNAPSHOT
+ org.springframework.boot
+ spring-boot-starter-parent
+ 1.5.2.RELEASE
@@ -21,6 +21,19 @@
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ org.springframework.boot
+ spring-boot-starter-freemarker
+
+
+ org.apache.shiro
+ shiro-spring-boot-web-starter
+ ${apache-shiro-core-version}
+
org.apache.shiro
shiro-core
diff --git a/apache-shiro/src/main/java/com/baeldung/ShiroSpringApplication.java b/apache-shiro/src/main/java/com/baeldung/ShiroSpringApplication.java
new file mode 100644
index 0000000000..e12d3ebffa
--- /dev/null
+++ b/apache-shiro/src/main/java/com/baeldung/ShiroSpringApplication.java
@@ -0,0 +1,45 @@
+package com.baeldung;
+
+import org.apache.shiro.realm.Realm;
+import org.apache.shiro.spring.web.config.DefaultShiroFilterChainDefinition;
+import org.apache.shiro.spring.web.config.ShiroFilterChainDefinition;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.context.annotation.Bean;
+
+/**
+ * Created by smatt on 21/08/2017.
+ */
+@SpringBootApplication
+public class ShiroSpringApplication {
+
+ private static final transient Logger log = LoggerFactory.getLogger(ShiroSpringApplication.class);
+
+ public static void main(String... args) {
+ SpringApplication.run(ShiroSpringApplication.class, args);
+ }
+
+
+ @Bean
+ public Realm realm() {
+ return new MyCustomRealm();
+ }
+
+
+ @Bean
+ public ShiroFilterChainDefinition shiroFilterChainDefinition() {
+ DefaultShiroFilterChainDefinition filter
+ = new DefaultShiroFilterChainDefinition();
+
+ filter.addPathDefinition("/secure", "authc");
+ filter.addPathDefinition("/**", "anon");
+
+ return filter;
+ }
+
+
+
+
+}
diff --git a/apache-shiro/src/main/java/com/baeldung/controllers/ShiroSpringController.java b/apache-shiro/src/main/java/com/baeldung/controllers/ShiroSpringController.java
new file mode 100644
index 0000000000..e6e72b2579
--- /dev/null
+++ b/apache-shiro/src/main/java/com/baeldung/controllers/ShiroSpringController.java
@@ -0,0 +1,105 @@
+package com.baeldung.controllers;
+
+import com.baeldung.models.UserCredentials;
+import org.apache.shiro.SecurityUtils;
+import org.apache.shiro.authc.AuthenticationException;
+import org.apache.shiro.authc.UsernamePasswordToken;
+import org.apache.shiro.subject.Subject;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.ModelMap;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.servlet.mvc.support.RedirectAttributes;
+
+import javax.servlet.http.HttpServletRequest;
+
+@Controller
+public class ShiroSpringController {
+
+
+
+ @GetMapping("/")
+ public String index() {
+ return "index";
+ }
+
+
+ @RequestMapping( value = "/login", method = {RequestMethod.GET, RequestMethod.POST})
+ public String login(HttpServletRequest req, UserCredentials cred, RedirectAttributes attr) {
+
+ if(req.getMethod().equals(RequestMethod.GET.toString())) {
+ return "login";
+ }
+ else {
+
+ Subject subject = SecurityUtils.getSubject();
+
+ if(!subject.isAuthenticated()) {
+ UsernamePasswordToken token = new UsernamePasswordToken(
+ cred.getUsername(), cred.getPassword(), cred.isRememberMe());
+ try {
+ subject.login(token);
+ } catch (AuthenticationException ae) {
+ ae.printStackTrace();
+ attr.addFlashAttribute("error", "Invalid Credentials");
+ return "redirect:/login";
+ }
+ }
+
+ return "redirect:/secure";
+ }
+ }
+
+
+ @GetMapping("/secure")
+ public String secure(ModelMap modelMap) {
+
+ Subject currentUser = SecurityUtils.getSubject();
+ String role = "", permission = "";
+
+ if(currentUser.hasRole("admin")) {
+ role = role + "You are an Admin";
+ }
+ else if(currentUser.hasRole("editor")) {
+ role = role + "You are an Editor";
+ }
+ else if(currentUser.hasRole("author")) {
+ role = role + "You are an Author";
+ }
+
+ if(currentUser.isPermitted("articles:compose")) {
+ permission = permission + "You can compose an article, ";
+ } else {
+ permission = permission + "You are not permitted to compose an article!, ";
+ }
+
+ if(currentUser.isPermitted("articles:save")) {
+ permission = permission + "You can save articles, ";
+ } else {
+ permission = permission + "\nYou can not save articles, ";
+ }
+
+ if(currentUser.isPermitted("articles:publish")) {
+ permission = permission + "\nYou can publish articles";
+ } else {
+ permission = permission + "\nYou can not publish articles";
+ }
+
+ modelMap.addAttribute("username", currentUser.getPrincipal());
+ modelMap.addAttribute("permission", permission);
+ modelMap.addAttribute("role", role);
+
+ return "secure";
+ }
+
+
+ @PostMapping("/logout")
+ public String logout() {
+ Subject subject = SecurityUtils.getSubject();
+ subject.logout();
+ return "redirect:/";
+ }
+
+}
diff --git a/apache-shiro/src/main/java/com/baeldung/models/UserCredentials.java b/apache-shiro/src/main/java/com/baeldung/models/UserCredentials.java
new file mode 100644
index 0000000000..51b429046a
--- /dev/null
+++ b/apache-shiro/src/main/java/com/baeldung/models/UserCredentials.java
@@ -0,0 +1,40 @@
+package com.baeldung.models;
+
+public class UserCredentials {
+
+ private String username;
+ private String password;
+ private boolean rememberMe = false;
+
+ public UserCredentials() {}
+
+ public String getUsername() {
+ return username;
+ }
+
+ public void setUsername(String username) {
+ this.username = username;
+ }
+
+ public String getPassword() {
+ return password;
+ }
+
+ public void setPassword(String password) {
+ this.password = password;
+ }
+
+ public boolean isRememberMe() {
+ return rememberMe;
+ }
+
+ public void setRememberMe(boolean rememberMe) {
+ this.rememberMe = rememberMe;
+ }
+
+ @Override
+ public String toString() {
+ return "username = " + getUsername()
+ + "\nrememberMe = " + isRememberMe();
+ }
+}
diff --git a/apache-shiro/src/main/resources/application.properties b/apache-shiro/src/main/resources/application.properties
new file mode 100644
index 0000000000..5bcb6b3352
--- /dev/null
+++ b/apache-shiro/src/main/resources/application.properties
@@ -0,0 +1,11 @@
+server.port=9000
+server.servlet-path=/
+server.context-path=/
+
+#shiro-spring-boot-config
+shiro.loginUrl = /login
+shiro.successUrl = /secure
+shiro.unauthorizedUrl = /login
+
+#freemarker
+spring.freemarker.suffix=.ftl
diff --git a/apache-shiro/src/main/resources/templates/index.ftl b/apache-shiro/src/main/resources/templates/index.ftl
new file mode 100644
index 0000000000..0210d656fc
--- /dev/null
+++ b/apache-shiro/src/main/resources/templates/index.ftl
@@ -0,0 +1,10 @@
+
+
+ Index
+
+
+ Welcome Guest!
+
+ Login
+
+
\ No newline at end of file
diff --git a/apache-shiro/src/main/resources/templates/login.ftl b/apache-shiro/src/main/resources/templates/login.ftl
new file mode 100644
index 0000000000..3a0552dc2e
--- /dev/null
+++ b/apache-shiro/src/main/resources/templates/login.ftl
@@ -0,0 +1,27 @@
+
+
+ Login
+
+
+Login
+
+
+
+
\ No newline at end of file
diff --git a/apache-shiro/src/main/resources/templates/secure.ftl b/apache-shiro/src/main/resources/templates/secure.ftl
new file mode 100644
index 0000000000..4466a0162f
--- /dev/null
+++ b/apache-shiro/src/main/resources/templates/secure.ftl
@@ -0,0 +1,15 @@
+
+
+ Secure
+
+
+Welcome ${username}!
+Role: ${role}
+Permissions
+${permission}
+
+
+
+
\ No newline at end of file