I have created a minimal example application with Spring-Boot (because of the "spring" tag) and Shiro for you, which you can find here on GitHub. The example application is based on the "hello world" RESTful web service with Spring application from the Spring docs. I have added Shiro to it via these changes (GitHub commit):
Add the shiro-spring dependency to pom.xml:
</dependencies>
[...]
<!-- Apache Shiro -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.3.2</version>
</dependency>
</dependencies>
Copy shiro.ini from the Shiro docs to resources:
# =============================================================================
# Tutorial INI configuration
#
# Usernames/passwords are based on the classic Mel Brooks' film "Spaceballs" :)
# =============================================================================
# -----------------------------------------------------------------------------
# Users and their (optional) assigned roles
# username = password, role1, role2, ..., roleN
# -----------------------------------------------------------------------------
[users]
root = secret, admin
guest = guest, guest
presidentskroob = 12345, president
darkhelmet = ludicrousspeed, darklord, schwartz
lonestarr = vespa, goodguy, schwartz
# -----------------------------------------------------------------------------
# Roles with assigned permissions
# roleName = perm1, perm2, ..., permN
# -----------------------------------------------------------------------------
[roles]
admin = *
schwartz = lightsaber:*
goodguy = winnebago:drive:eagle5
Configure ShiroFilter, SecurityManager with IniRealm, and Shiro annotations in Application.java (adapted from here):
@SpringBootApplication
public class Application {
[...]
@Bean(name = "shiroFilter")
public FilterRegistrationBean shiroFilter() throws Exception {
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setFilter((AbstractShiroFilter) getShiroFilterFactoryBean().getObject());
registration.setDispatcherTypes(EnumSet.allOf(DispatcherType.class));
return registration;
}
@Bean
public ShiroFilterFactoryBean getShiroFilterFactoryBean() {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager());
Map<String, String> filterChainDefinitionMap = shiroFilterFactoryBean.getFilterChainDefinitionMap();
filterChainDefinitionMap.put("/**", "authcBasic");
return shiroFilterFactoryBean;
}
@Bean(name = "securityManager")
public DefaultWebSecurityManager securityManager() {
DefaultWebSecurityManager dwsm = new DefaultWebSecurityManager();
dwsm.setRealm(getShiroIniRealm());
final DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
// disable session cookie
sessionManager.setSessionIdCookieEnabled(false);
dwsm.setSessionManager(sessionManager);
return dwsm;
}
@Bean(name = "shiroIniRealm")
@DependsOn("lifecycleBeanPostProcessor")
public IniRealm getShiroIniRealm() {
return new IniRealm("classpath:shiro.ini");
}
@Bean(name = "lifecycleBeanPostProcessor")
public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
return new LifecycleBeanPostProcessor();
}
@Bean
public DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator() {
DefaultAdvisorAutoProxyCreator daap = new DefaultAdvisorAutoProxyCreator();
daap.setProxyTargetClass(true);
return daap;
}
@Bean
public AuthorizationAttributeSourceAdvisor getAuthorizationAttributeSourceAdvisor() {
AuthorizationAttributeSourceAdvisor aasa = new AuthorizationAttributeSourceAdvisor();
aasa.setSecurityManager(securityManager());
return new AuthorizationAttributeSourceAdvisor();
}
}
Add @RequiresRoles annotation with parameter "admin" to GreetingController for testing purposes:
@RestController
public class GreetingController {
private static final String template = "Hello, %s!";
private final AtomicLong counter = new AtomicLong();
@RequestMapping("/greeting")
@RequiresRoles(value = {"admin"})
public Greeting greeting(@RequestParam(value="name", defaultValue="World") String name) {
return new Greeting(counter.incrementAndGet(),
String.format(template, name));
}
}
Use the following commands to check out and run the application:
git clone https://github.com/opncow/gs-rest-service.git
cd gs-rest-service/complete/
./mvnw spring-boot:run
Verify that Shiro is working (use HttpRequester or similar plugin to create the following requests):
User "root" (has "admin" role) with password "secret" (Base64 encoded username:password as value of the Authorization header)
GET http://localhost:8080/greeting
Authorization: Basic cm9vdDpzZWNyZXQ=
-- response --
200
Set-Cookie: rememberMe=deleteMe; Path=/; Max-Age=0; Expires=Thu, 11-May-2017 00:29:44 GMT
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Date: Fri, 12 May 2017 00:29:44 GMT
{"id":1,"content":"Hello, World!"}
User "guest" with password "guest" (no "admin" role):
GET http://localhost:8080/greeting
Authorization: Basic Z3Vlc3Q6Z3Vlc3Q=
-- response --
500
Set-Cookie: rememberMe=deleteMe; Path=/; Max-Age=0; Expires=Thu, 11-May-2017 00:44:18 GMT rememberMe=deleteMe; Path=/; Max-Age=0; Expires=Thu, 11-May-2017 00:44:18 GMT
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Date: Fri, 12 May 2017 00:44:18 GMT
Connection: close
{"timestamp":1494549858572,"status":500,"error":"Internal Server Error","exception":"org.apache.shiro.authz.UnauthorizedException","message":"Subject does not have role [admin]","path":"/greeting"}
As can be seen, in the second request, the user guest is authenticated, however not authorized to use the greeting resource because of lacking the "admin" role (which means that the annotation is working).
This is the most minimal example I could imagine. It uses Shiro's .ini configuration/realm for users, passwords, and roles. For a real world project you will likely have to use a more sophisticated realm implementation such as Shiro's JdbcRealm