Spring Boot Shro
14126 ワード
シンロコアAPI
Subject: ( Subject)。
principal: 。 、 、 , 。
credential: 。 , 。
SecurityManager: ( Realm), 。
Realm:Shiro 。
Cryptography: , , , 。
Caching: , , 、 / , 。
CacheManager: , 、 、 。
SessionManager: , , , 。
SessionDAO: 。
Shro認証と授権 :
Step1: Subject.login(token) , AuthenticationToken Token。
Step2: Subject SecurityManager(Shiro ) 。
Step3、4、5:SecurityManager Realm 。
( : 、 ):
(Permission): ( 、 、 、 )。
(Role): , 。
(User): Shiro , , Subject 。
:
, redis session, 。
, 。
session sessionId, , cookie , session redis 。
, session expireTime。
, cookie request headers 。
sessionId redis 。
, , , 。
Spring Boot Shro依存
org.apache.shiro
shiro-spring
カスタムRealm Realm AuthorizingRealm , , Realm 。
:
doGetAuthenticationInfo() : , 。
doGetAuthorizationInfo() : 。
public class CustomRealm extends AuthorizingRealm {
@Autowired
private UserService userService;
/**
*
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
//
String account = (String) principals.getPrimaryPrincipal();
//
User user = userService.getUserByAccount(account);
//
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
Set roles = new HashSet();
if (user.getAdmin()) {
roles.add(Base.ROLE_ADMIN);
}
authorizationInfo.setRoles(roles);
return authorizationInfo;
}
/**
*
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
//
String account = (String) token.getPrincipal();
//
User user = userService.getUserByAccount(account);
if (null == user) {
throw new UnknownAccountException(); //
}
if (UserStatus.blocked.equals(user.getStatus())) {
throw new LockedAccountException(); //
}
// ,
return new SimpleAuthenticationInfo(
user.getAccount(),
user.getPassword(),
ByteSource.Util.bytes(user.getSalt()), // ( )
getName()
);
}
}
カスタムSession DAOCachemanager 、 , Session 。
SessionDAO Session , Redis 。
SessionDAO:MemorySessionDAO:
Session , ConcurrentHashMap。
public class MemorySessionDAO extends AbstractSessionDAO {
private ConcurrentMap sessions = new ConcurrentHashMap();
protected Serializable doCreate(Session session) {
Serializable sessionId = this.generateSessionId(session);
this.assignSessionId(session, sessionId);
this.storeSession(sessionId, session);
return sessionId;
}
}
/**
* Session Redis
*/
public class CustomSessionDAO extends CachingSessionDAO {
@Autowired
private RedisTemplate redisTemplate;
// :30
public final static long DEFAULT_EXPIRE = 60 * 30;
@Override
protected Serializable doCreate(Session session) {
// SessionId
Serializable sessionId = generateSessionId(session);
// SessionId
assignSessionId(session, sessionId);
// Session
redisTemplate.opsForValue().set(sessionId.toString(), session, DEFAULT_EXPIRE, TimeUnit.SECONDS);
return sessionId;
}
@Override
protected void doUpdate(Session session) {
if (session instanceof ValidatingSession && !((ValidatingSession) session).isValid()) {
// /
return;
}
redisTemplate.opsForValue().set(session.getId().toString(), session, DEFAULT_EXPIRE, TimeUnit.SECONDS);
}
@Override
protected void doDelete(Session session) {
redisTemplate.delete(session.getId().toString());
}
@Override
protected Session doReadSession(Serializable sessionId) {
return (Session) redisTemplate.opsForValue().get(sessionId.toString());
}
}
カスタムSession Manager(完璧を待つ)public class CustomSessionManager extends DefaultWebSessionManager {
public static final String TOKEN = "token";
/**
* , token 。
* , token, request 。
* , request , 。
* token , cookie , 。
*/
@Override
public Serializable getSessionId(SessionKey key) {
Serializable sessionId = key.getSessionId();
if(sessionId == null && WebUtils.isWeb(key)){
HttpServletRequest request = WebUtils.getHttpRequest(key);
HttpServletResponse response = WebUtils.getHttpResponse(key);
sessionId = this.getSessionId(request,response);
}
HttpServletRequest request = WebUtils.getHttpRequest(key);
request.setAttribute(TOKEN,sessionId.toString());
return sessionId;
}
/**
* DefaultWebSessionManager , Cookie SessionId。
* , SessionId request header 。
*/
@Override
protected Serializable getSessionId(ServletRequest request, ServletResponse response) {
HttpServletRequest httpRequest = (HttpServletRequest) request;
String id = httpRequest.getHeader(TOKEN);
if (!StringUtils.isEmpty(id)) {
request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE, ShiroHttpServletRequest.COOKIE_SESSION_ID_SOURCE);
request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID, id);
request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_IS_VALID, Boolean.TRUE);
return id;
}
return super.getSessionId(request, response);
}
}
プロファイル@Configuration
public class ShiroConfig {
/**
* ShiroFilterFactoryBean
*/
@Bean
public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
// securityManager
shiroFilterFactoryBean.setSecurityManager(securityManager);
//LinkedHashMap ,
Map filterMap = new LinkedHashMap();
filterMap.put("/static/**", "anon"); //
filterMap.put("/login", "anon");
filterMap.put("/register", "anon");
// , Shiro , LoginUrl
filterMap.put("/logout", "logout");
filterMap.put("/**/create", "authc"); //
filterMap.put("/**/update", "authc");
filterMap.put("/**/delete", "authc");
filterMap.put("/upload", "authc");
filterMap.put("/admin", "perms[admin]"); // , :perms["admin,user"]
filterMap.put("/admin", "role[admin]"); //
filterMap.put("/**", "anon");
// URL, URL
shiroFilterFactoryBean.setLoginUrl("/login");
// URL
shiroFilterFactoryBean.setSuccessUrl("/index");
// , URL
shiroFilterFactoryBean.setUnauthorizedUrl("/unAuthorized");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);
return shiroFilterFactoryBean;
}
/**
* :DefaultWebSecurityManager
*/
@Bean
public SecurityManager securityManager(CustomRealm realm, SessionManager sessionManager) {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(realm);
securityManager.setSessionManager(sessionManager);
return securityManager;
}
/**
* Realm
*/
@Bean
public CustomRealm customRealm() {
CustomRealm shiroRealm = new CustomRealm();
//
HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();
matcher.setHashAlgorithmName("md5"); //
matcher.setHashIterations(2); //
shiroRealm.setCredentialsMatcher(matcher);
return shiroRealm;
}
/**
* SessionManager
*/
@Bean
public SessionManager sessionManager() {
CustomSessionManager customSessionManager = new CustomSessionManager();
//session :1 ( )
customSessionManager.setGlobalSessionTimeout(60 * 60 * 1000);
customSessionManager.setSessionDAO(new CustomSessionDAO());
return customSessionManager;
}
/**
* Spring Boot Shiro
*/
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
return authorizationAttributeSourceAdvisor;
}
}
Sessionのクエリ、更新SimpleSession :
Serializable id:session id;
Date startTimestamp:session ;
Date stopTimestamp:session ;
Date lastAccessTime:session , startTimestamp
long timeout:session , 30
boolean expired:session
Map
Shroは3つの方式の授権をサポートします.1、 , if/else
Subject subject = SecurityUtils.getSubject();
if(subject.hasRole("admin")) {
// ,
} else {
// ,
}
2、 , Java
@RequiresPermissions("admin")
public List listUser() {
// ,
}
3、JSP/GSP , JSP/GSP
Spring Boot統合ShroとEhcache(完璧にする予定) ehcache.xml:
application.xml :spring.cache.ehcache.config=classpath:ehcache.xml
ControllerとServiceは使用します.Controller:
@PostMapping("/login")
public Result login(@RequestBody User user) {
Result r = new Result();
// Subject
Subject subject = SecurityUtils.getSubject();
//
UsernamePasswordToken token = new UsernamePasswordToken(user.getAccount(), user.getPassword());
try {
// ( UserRealm )
subject.login(token);
//
User currentUser = userService.getUserByAccount(user.getAccount());
subject.getSession().setAttribute(Base.CURRENT_USER, currentUser);
r.setResultCode(ResultCode.SUCCESS);
r.getData().put("token", subject.getSession().getId());
} catch (UnknownAccountException e) {
r.setResultCode(ResultCode.USER_NOT_EXIST); //
} catch (LockedAccountException e) {
r.setResultCode(ResultCode.USER_ACCOUNT_FORBIDDEN); //
}catch (IncorrectCredentialsException e) {
r.setResultCode(ResultCode.USER_LOGIN_PASSWORD_ERROR); //
} catch (AuthenticationException e) {
r.setResultCode(ResultCode.USER_LOGIN_ERROR); // ( )
}
return r;
}
@PostMapping("/register")
public Result register(@RequestBody User user) {
Result r = new Result();
User temp = userService.getUserByAccount(user.getAccount());
if (null != temp) {
r.setResultCode(ResultCode.USER_HAS_EXISTED);
return r;
}
userService.saveUser(user);
r.setResultCode(ResultCode.SUCCESS);
return r;
}
Service:
@Override
@Transactional
public void saveUser(User user) {
//
String newPassword = new SimpleHash(
"md5",user.getPassword(),
ByteSource.Util.bytes("salt"),2).toHex();
user.setPassword(newPassword);
return userRepository.save(user);
}