A api to support H5, PC and APP three front-end, if you use session if not very friendly app, and the session in question cross-domain attacks, so I chose JWT
1. Import dependencies
<dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.3.2</version> </dependency> <dependency> <groupId>com.auth0</groupId> <artifactId>java-jwt</artifactId> <version>3.2.0</version> </dependency>
2. Custom JWTToken
import org.apache.shiro.authc.AuthenticationToken; public class JwtToken implements AuthenticationToken { private String token; public JwtToken(String token) { this.token = token; } @Override public Object getPrincipal() { return token; } @Override public Object getCredentials() { return token; } }
Tools
import com.auth0.jwt.JWT; import com.auth0.jwt.JWTVerifier; import com.auth0.jwt.algorithms.Algorithm; import com.auth0.jwt.exceptions.JWTDecodeException; import com.auth0.jwt.interfaces.DecodedJWT; import java.io.UnsupportedEncodingException; import java.util.Date; public class JwtUtils { // 过期时间30天 private static final long EXPIRE_TIME = 24 * 60 * 30 * 1000; /** * 校验token是否正确 * * @param token 密钥 * @param username 登录名 * @param password 密码 * @return */ public static boolean verify(String token, String username, String password) { try { Algorithm algorithm = Algorithm.HMAC256(password); JWTVerifier verifier = JWT.require(algorithm).withClaim("userName", username).build(); DecodedJWT jwt = verifier.verify(token); return true; } catch (Exception e) { return false; } } /** * 获取登录名 * * @param token * @return */ public static String getUsername(String token) { try { DecodedJWT jwt = JWT.decode(token); return jwt.getClaim("userName").asString(); } catch (JWTDecodeException e) { return null; } } /** * 生成签名 * * @param username * @param password * @return */ public static String sign(String username, String password) { try { // 指定过期时间 Date date = new Date(System.currentTimeMillis() + EXPIRE_TIME); Algorithm algorithm = Algorithm.HMAC256(password); return JWT.create() .withClaim("userName", username) .withExpiresAt(date) .sign(algorithm); } catch (UnsupportedEncodingException e) { return null; } } }
3. Custom realm
import com.system.authorization.model.JwtToken; import com.system.authorization.model.MzUser; import com.system.authorization.service.MzUserService; import com.system.authorization.utils.JwtUtils; import org.apache.shiro.authc.*; import org.apache.shiro.authz.AuthorizationInfo; import org.apache.shiro.authz.SimpleAuthorizationInfo; import org.apache.shiro.realm.AuthorizingRealm; import org.apache.shiro.subject.PrincipalCollection; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import java.util.Set; public class JwtShiroRealm extends AuthorizingRealm { private Logger logger = LoggerFactory.getLogger(this.getClass()); @Autowired private MzUserService mzUserService; /** * 使用JWT代替原生Token * @param token * @return */ @Override public boolean supports(AuthenticationToken token) { return token instanceof JwtToken; } //权限验证 @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { logger.info("doGetAuthorizationInfo:" + principalCollection.toString()); String userName = JwtUtils.getUsername(principalCollection.toString()); //获取权限数据 Set<String> permissions = mzUserService.getPermissionByUserName(userName); SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo(); simpleAuthorizationInfo.setStringPermissions(permissions); return simpleAuthorizationInfo; } / ** * Authentication: Authentication is used to verify user identity * Use this method to verify that the default user name is correct or not, throw an exception error * / @Override protected AuthenticationInfo doGetAuthenticationInfo (AuthenticationToken AuthenticationToken) throws AuthenticationException { String token = authenticationToken.getPrincipal () .toString (); System.out.println ( "Realm verification:" + token); String the userName = JwtUtils.getUsername (token); System.out.println ( "Realm verify the user name:" + the userName); MzUser mzUser = mzUserService.queryByUserName (the userName); IF(mzUser == null ) { the throw new new of AuthenticationException ( "token verification failure, insufficient authority" ); } IF (! {JwtUtils.verify (token, the userName, mzUser.getPassword ())) the throw new new UnknownAccountException ( "token validation fails, insufficient permissions " ); } return new new SimpleAuthenticationInfo (token, token," realm " ); } }
4. Custom filter
import com.system.authorization.model.JwtToken; import org.apache.commons.lang3.StringUtils; import org.apache.http.HttpStatus; import org.apache.shiro.authc.UnknownAccountException; import org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter; import org.apache.shiro.web.util.WebUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; importjava.io.IOException; public class JwtAuthFilter the extends BasicHttpAuthenticationFilter { Private Logger Logger = LoggerFactory.getLogger ( the this .getClass ()); // login ID Private static String LOGIN_SIGN = "the auth-token-X" ; / ** * Detection user whether the login * which detects whether the Authorization header field to * * @param Request * @param the Response * @return * / @Override protected boolean isLoginAttempt(ServletRequest request, ServletResponse response) { HttpServletRequest httpRequest = WebUtils.toHttp(request); String authorization = httpRequest.getHeader(LOGIN_SIGN); return StringUtils.isNoneBlank(authorization); } @Override protected boolean executeLogin(ServletRequest request, ServletResponse response) throws Exception { HttpServletRequest httpRequest = WebUtils.toHttp(request); String token = httpRequest.getHeader(LOGIN_SIGN); JwtToken jwtToken = newJwtToken (token); // submitted to log in to the realm, if the error would be afraid proudly abnormal and captured, if not Throws an exception to true getSubject (Request, the Response) your .login (jwtToken); return to true ; } @Override protected Boolean isAccessAllowed (the ServletRequest request, Response the ServletResponse, Object mappedValue) { System.out.println ( "start jwt check" ); // if not login request IF (isLoginAttempt (request, Response)) { the try { the executeLogin (request, Response); } the catch (Exception E) { // throw new TSharkException("登录权限不足!", e); throw new UnknownAccountException("token验证失败,权限不足"); } } System.out.println("jwt 校验通过"); return true; } @Override protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws IOException { HttpServletResponse httpResponse = WebUtils.toHttp(response); httpResponse.setCharacterEncoding("UTF-8"); httpResponse.setContentType("file application / JSON; charset = UTF-. 8" ); httpResponse.setStatus (org.apache.http.HttpStatus.SC_UNAUTHORIZED); System.out.println ( "token validation fails, no access" ); return to false ; } / ** * support for cross-domain * * @param Request * @param Response * @return * @throws Exception * / @Override protected Boolean The preHandle (the ServletRequest Request, the ServletResponse Response) throws Exception { HttpServletRequest httpServletRequest = (HttpServletRequest) request; HttpServletResponse httpServletResponse = (HttpServletResponse) response; httpServletResponse.setHeader("Access-control-Allow-Origin", httpServletRequest.getHeader("Origin")); httpServletResponse.setHeader("Access-Control-Allow-Methods", "GET,POST,OPTIONS,PUT,DELETE"); httpServletResponse.setHeader("Access-Control-Allow-Headers", httpServletRequest.getHeader("Access-Control-Request-Headers")); // 跨域时会首先发送一个option请求,这里我们给option请求直接返回正常状态 if (httpServletRequest.getMethod().equals(RequestMethod.OPTIONS.name())) { httpServletResponse.setStatus(HttpStatus.OK.value()); return false; } return super.preHandle(request, response); } }
Authorization filter
import org.apache.http.HttpStatus; import org.apache.shiro.subject.Subject; import org.apache.shiro.web.filter.authz.AuthorizationFilter; import org.apache.shiro.web.util.WebUtils; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletResponse; import java.io.IOException; public class RolesAndPermissionFilter extends AuthorizationFilter { @Override protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws{Exception System.out.println ( "Start Roles permission check" ); // Get Interface request address String path = WebUtils.toHttp (Request) .getRequestURI (); the Subject Subject = the getSubject (Request, Response); // database request address is stored in the interface, where the interface address of the current request to verify whether the currently logged in user exists and, if it is verified IF (subject.isPermitted (path)) return to true ; System.out.println ( "Roles permission verification failed " ); return to false ; } @Override protected Boolean onAccessDenied(ServletRequest request, ServletResponse response) throws IOException { HttpServletResponse httpResponse = WebUtils.toHttp(response); httpResponse.setCharacterEncoding("UTF-8"); httpResponse.setContentType("application/json;charset=utf-8"); httpResponse.setStatus(HttpStatus.SC_UNAUTHORIZED); return false; } }
The configuration information, the injection spring containers
import com.system.authorization.filter.JwtAuthFilter; import com.system.authorization.filter.RolesAndPermissionFilter; import com.system.authorization.realm.JwtShiroRealm; import org.apache.shiro.mgt.DefaultSecurityManager; import org.apache.shiro.mgt.DefaultSessionStorageEvaluator; import org.apache.shiro.mgt.DefaultSubjectDAO; import org.apache.shiro.mgt.SecurityManager; import org.apache.shiro.realm.Realm; import org.apache.shiro.spring.LifecycleBeanPostProcessor; import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor; import org.apache.shiro.spring.web.ShiroFilterFactoryBean; import org.apache.shiro.web.mgt.DefaultWebSecurityManager; import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator; import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.DependsOn; import javax.servlet.Filter; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Map; @Configuration @ConditionalOnWebApplication public class ShiroConfig { @Bean public Realm jwtShiroRealm() { return new JwtShiroRealm(); } @Bean public SecurityManager securityManager() { DefaultSecurityManager defaultSecurityManager = new DefaultWebSecurityManager(); defaultSecurityManager.setRealm(jwtShiroRealm()); // 关闭自带session DefaultSessionStorageEvaluator evaluator = new DefaultSessionStorageEvaluator(); evaluator.setSessionStorageEnabled(false); DefaultSubjectDAO subjectDAO = new DefaultSubjectDAO(); subjectDAO.setSessionStorageEvaluator(evaluator); defaultSecurityManager.setSubjectDAO(subjectDAO); return defaultSecurityManager; } @Bean(name = "shiroFilter") public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) { ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean(); //将自定义的过滤器注入 Map<String, Filter> filterMap = new LinkedHashMap<>(); filterMap.put("jwt", new new JwtAuthFilter ()); filterMap.put ( "permission", new new RolesAndPermissionFilter ()); factoryBean.setFilters (filterMap); factoryBean.setSecurityManager (securityManager); // filter rules defined the Map <String, String> = filterRuleMap new new the HashMap < > (); // All requests must go through jwt, permission filter filterRuleMap.put ( "/ **", "jwt, permission" ); // the login interface can not verify filterRuleMap.put ( "/ mz / the User / the Login "," anon " ); factoryBean.setFilterChainDefinitionMap (filterRuleMap); // set the login page, home page, page validation fails factoryBean.setLoginUrl("https://www.baidu.com"); factoryBean.setSuccessUrl("https://www.cnblogs.com/gyli20170901/"); factoryBean.setUnauthorizedUrl("/403"); return factoryBean; } @Bean @DependsOn("lifecycleBeanPostProcessor") public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() { DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator(); defaultAdvisorAutoProxyCreator.setProxyTargetClass(true); return defaultAdvisorAutoProxyCreator; } @Bean public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() { return new LifecycleBeanPostProcessor(); } @Bean public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) { AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor(); advisor.setSecurityManager(securityManager); return advisor; } }
Reference: https://yq.aliyun.com/articles/646440