大多数项目的权限管理都是通过Role来实现的。 如果当前用户拥有指定的Role才能进行相应的操作。这一节就学习如何在Restlet中使用Role进行权限控制。
首先,定义一个Account类,模拟我们系统中的用户。
public class Account {
private String username ;
private String password ;
private String email ;
private String[] roles ;
public Account(String username, String password, String email) {
super();
this.username = username;
this.password = password;
this.email = email;
}
public Account(String username, String password, String email,
String[] roles) {
super();
this.username = username;
this.password = password;
this.email = email;
this.roles = roles;
}
public Account() {
super();
}
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 String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String[] getRoles() {
return roles;
}
public void setRoles(String[] roles) {
this.roles = roles;
}
}
然后是AccountManager(模拟数据库操作)
public class AccountManager {
private List<Account> accounts = new ArrayList<Account>() ;
{
//初始化一些账户
accounts.add(new Account("111", "111", "111@163.com", new String[]{"Admin" , "Common" , "Manager"})) ;
accounts.add(new Account("222", "222", "222@163.com", new String[]{"Common"})) ;
accounts.add(new Account("333", "333", "333@163.com", new String[]{"Common"})) ;
accounts.add(new Account("444", "444", "444@163.com", new String[]{"Manager" , "Common"})) ;
}
/**
* 根据用户名查找用户
*/
public Account findUserByName(String username){
for (Account account : accounts) {
if(account.getUsername().equals(username)){
return account ;
}
}
return null ;
}
/**
* 根据用户名查找用户所拥有的权限
*/
public String[] findRoleByUsername(String username){
for (Account account : accounts) {
if(account.getUsername().equals(username)){
return account.getRoles() ;
}
}
return null ;
}
}
接下来就是对账户的校验器
/**
* 自定义的校验器
*/
public class MySecretVerifier extends SecretVerifier{
private AccountManager accountManager = new AccountManager() ;
@Override
public int verify(String identifier, char[] secret) {
System.out.printf("username:%s password:%s%n" , identifier , new String(secret) );
Account account = accountManager.findUserByName(identifier);
if(account != null){
if(compare(account.getPassword().toCharArray(), secret)){
return RESULT_VALID ;
}
}
return RESULT_INVALID;
}
}
接下来编写服务端资源
public class MovieServerResource extends ServerResource implements MovieResource{
public String uploadMovie(Movie movie) throws IOException{
String result = String.format("upload movie{name:%s size:%d minutes:%d} success!" ,
movie.getName() ,
movie.getSize(),
movie.getMinutes());
return result ;
}
@Override
public Representation getMovieInfo() {
//如果拥有Manager或Admin的Role才能访问本方法
if(isInRole("Manager") || isInRole("Admin") ){
return new StringRepresentation("movie info");
}else{
return new StringRepresentation("Permission Denied");
}
}
}
配置Application
public class MovieApplication extends Application{
private AccountManager accountManager = new AccountManager() ;
public MovieApplication(){
setAuthor("zhoufeng");
/*
* 在Application中,必须同时也包含所有该Application会用到的Role
* 从源码IsInRole()方法的实现就能明白
* public boolean isInRole(String roleName) {
return getClientInfo().getRoles().contains(
getApplication().getRole(roleName));
}
* */
getRoles().add(new Role("Common"));
getRoles().add(new Role("Manager"));
getRoles().add(new Role("Admin"));
}
/**
* 注意:Router 与 ChallengeAuthenticator 均是Restlet的子类
*/
@Override
public Restlet createInboundRoot() {
Router router = new Router(getContext());
//绑定资源
router.attach("/" , MovieServerResource.class);
//创建认证器
ChallengeAuthenticator authenticator = new ChallengeAuthenticator(getContext(), ChallengeScheme.HTTP_BASIC,
"Movie Realm");
/**
* 注意:
* 当客户端访问资源时,首先经过Verifier验证用户名与密码,如果校验失败,就会直接返回客户端error:401 Unauthorized校验失败
* 然后再通过Enroler为ClientInfo中User查询出Roles
* 最后在ServerResource中就可以通过isInRole()方法判断访问该方法的当前用户是否拥有指定的角色。
*/
//使用自定义的验证器
authenticator.setVerifier(new MySecretVerifier());
/* 登记用户所拥有的角色 */
authenticator.setEnroler(new Enroler() {
@Override
public void enrole(ClientInfo clientInfo) {
String[] roles = accountManager.
findRoleByUsername(clientInfo.getUser().getIdentifier());
for (String role : roles) {
clientInfo.getRoles().add(getApplication().getRole(role)) ;
}
}
});
//将路由器放在认证器之后
authenticator.setNext(router);
//返回认证器
return authenticator ;
}
}
启动服务器
public class MovieServer {
public static void main(String[] args) throws Exception {
Component comp = new Component() ;
comp.getServers().add(Protocol.HTTP , 8888) ;
MovieApplication movieApp = new MovieApplication() ;
comp.getDefaultHost().attach(movieApp);
comp.start();
}
}
然后就可以编写客户端测试。
public class MovieClient {
/**
* 不使用用户名密码直接访问Get方法,将会抛出异常
*/
@Test
public void test01() throws IOException{
ClientResource cr = new ClientResource("http://localhost:8888/");
cr.get().write(System.out);
}
/**
* 加入用户名密码访问Get方法,成功得到返回值
*/
@Test
public void test02() throws IOException{
ClientResource cr = new ClientResource("http://localhost:8888/");
cr.setChallengeResponse(ChallengeScheme.HTTP_BASIC ,
"111", "111");
cr.get().write(System.out);
}
}