SpringBoot integrates Shiro password login and mail verification code login functions of multi Realm authentication
- 2021-08-31 07:58:46
- OfStack
Import dependencies (pom. xml)
<!-- Integration Shiro Security framework -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.0</version>
</dependency>
<!-- Integration jwt Realization token Certification -->
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.2.0</version>
</dependency>
Create the ShiroConfig configuration class under the SpringBoot project configuration config package
@Configuration
public class ShiroConfig {
/**
* ShiroFilterFactoryBean
* <p>
* anon Access without authentication
* authc : Must be authenticated to access
* user : Must have Remember me Function can only be used
* perms Have permissions on a resource to access
* role Have a role permission to access
*/
@Bean
public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager defaultWebSecurityManager) {
ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();
// Setting up Security Manager
factoryBean.setSecurityManager(defaultWebSecurityManager);
// Add shiro Built-in filter of
Map<String, String> filterMap = new LinkedHashMap<>();
// Release interfaces that do not require permission authentication
// Home page of website
filterMap.put("/", "anon");
filterMap.put("/index", "anon");
filterMap.put("/index.html", "anon");
// Do not verify the jump interface
filterMap.put("/into/**", "anon");
// Interfaces that require permission authentication
// Verify jump interface
filterMap.put("/verifyInto/**", "authc");
factoryBean.setFilterChainDefinitionMap(filterMap);
// Access unauthorized resources
factoryBean.setLoginUrl("redirect:/into/login");
// Object that does not have time-limited jump url
factoryBean.setUnauthorizedUrl("redirect:/into/login");
return factoryBean;
}
/**
* Management shiro Life cycle of
*/
@Bean("lifecycleBeanPostProcessor")
public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
return new LifecycleBeanPostProcessor();
}
/**
* Injection Password login CustomRealm
*/
@Bean
@DependsOn("lifecycleBeanPostProcessor")
public UserPasswordRealm userPasswordRealm() {
return new UserPasswordRealm();
}
/**
* Injection Mailbox authentication login EmailRealm
*/
@Bean
@DependsOn("lifecycleBeanPostProcessor")
public UserEmailRealm userEmailRealm() {
return new UserEmailRealm();
}
/**
* Default Security Manager
*/
@Bean
public DefaultWebSecurityManager securityManager(UserPasswordRealm userPasswordRealm, UserEmailRealm userEmailRealm, AbstractAuthenticator abstractAuthenticator) {
DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
List<Realm> realms = new ArrayList<>();
realms.add(userPasswordRealm);
realms.add(userEmailRealm);
defaultWebSecurityManager.setRealms(realms);
// Remember me
defaultWebSecurityManager.setRememberMeManager(cookieRememberMeManager());
defaultWebSecurityManager.setAuthenticator(abstractAuthenticator);
return defaultWebSecurityManager;
}
/**
* Authenticator Add our custom authentication to the authenticator
*/
@Bean
public AbstractAuthenticator abstractAuthenticator(UserPasswordRealm userPasswordRealm, UserEmailRealm userEmailRealm) {
// Custom modular authenticator for solving multiple realm Throw an exception question
// I didn't use custom exception at first, and found that no matter whether the account password is wrong or what is wrong
//shiro Will only throw 1 A AuthenticationException Anomaly
ModularRealmAuthenticator authenticator = new MyCustomModularRealmAuthenticator();
// Authentication policy: AtLeastOneSuccessfulStrategy( Default ) , AllSuccessfulStrategy , FirstSuccessfulStrategy
authenticator.setAuthenticationStrategy(new AtLeastOneSuccessfulStrategy());
// Join realms
List<Realm> realms = new ArrayList<>();
realms.add(userPasswordRealm);
realms.add(userEmailRealm);
authenticator.setRealms(realms);
return authenticator;
}
/**
* Join shiro Annotation Proxy generator Sectional plane
*/
@Bean
@DependsOn({"lifecycleBeanPostProcessor"})
public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator() {
DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
advisorAutoProxyCreator.setProxyTargetClass(true);
return advisorAutoProxyCreator;
}
/**
* Join shiro Annotation Tangent point
*/
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(DefaultWebSecurityManager securityManager) {
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
return authorizationAttributeSourceAdvisor;
}
/**
* Settings cookie Remember I generated cookie
*/
@Bean
public CookieRememberMeManager cookieRememberMeManager() {
CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();
cookieRememberMeManager.setCookie(rememberMeCookie());
return cookieRememberMeManager;
}
/**
* Settings cookie Effective time
*/
@Bean
public SimpleCookie rememberMeCookie() {
/* This parameter is cookie The name of the front-end page, corresponding to the checkbox Adj. name=remremberMe*/
SimpleCookie simpleCookie = new SimpleCookie("rememberMe");
/*cookie The valid time of is 30 Days, unit seconds */
simpleCookie.setMaxAge(259200);
return simpleCookie;
}
}
Create a custom validator MyCustomModularRealmAuthenticator class
public class MyCustomModularRealmAuthenticator extends ModularRealmAuthenticator {
@Override
protected AuthenticationInfo doMultiRealmAuthentication(Collection<Realm> realms, AuthenticationToken token) {
AuthenticationStrategy authenticationStrategy = this.getAuthenticationStrategy();
AuthenticationInfo authenticationInfo = authenticationStrategy.beforeAllAttempts(realms, token);
Iterator var5 = realms.iterator();
while (var5.hasNext()) {
Realm realm = (Realm) var5.next();
authenticationInfo = authenticationStrategy.beforeAttempt(realm, token, authenticationInfo);
if (realm.supports(token)) {
AuthenticationInfo info = null;
Throwable t = null;
info = realm.getAuthenticationInfo(token);
authenticationInfo = authenticationStrategy.afterAttempt(realm, token, info, authenticationInfo, t);
}
}
authenticationInfo = authenticationStrategy.afterAllAttempts(token, authenticationInfo);
return authenticationInfo;
}
}
Verify authorization UserPasswordRealm class when creating password login
@Component
public class UserPasswordRealm extends AuthorizingRealm {
// Inject user service
@Autowired
private UserMapper userMapper;
/**
* Authorization
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
System.out.println(" Password Authorization doGetAuthorizationInfo --- ");
return null;
}
/**
* Certification
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
System.out.println(" Password authentication doGetAuthenticationInfo --- ");
UsernamePasswordToken userToken = (UsernamePasswordToken) token;
// Connect to a database Query user data
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.eq("user_name", userToken.getUsername());
User user = userMapper.selectOne(wrapper);
// Authenticate the user
if (user == null) {
throw new UnknownAccountException();
}
return new SimpleAuthenticationInfo("", user.getUserPassword(), "");
}
/**
* Used to determine whether to use the current realm
*
* @param var1 Incoming token
* @return true Just use, false You don't use it
*/
@Override
public boolean supports(AuthenticationToken var1) {
return var1 instanceof UsernamePasswordToken;
}
}
Create Mail Verification Code Login Verification Authorization UserEmailRealm Class
@Component
public class UserEmailRealm extends AuthorizingRealm {
// Inject user service
@Autowired
UserService userService;
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
System.out.println(" Mailbox login authorization doGetAuthorizationInfo --- ");
return null;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
System.out.println(" E-mail login authentication doGetAuthenticationInfo --- ");
UserEmailToken userEmailToken = (UserEmailToken) token;
String userEmail = (String) userEmailToken.getPrincipal();
// Connect to a database Query user data
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.eq("user_email", userEmail);
User user = userService.getOne(wrapper);
// Because there is no password and the verification code is verified before
if (user == null) {
throw new UnknownAccountException();
}
return new SimpleAuthenticationInfo("", userEmail, "");
}
/**
* Used to determine whether to use the current realm
*
* @param var1 Incoming token
* @return true Just use, false You don't use it
*/
@Override
public boolean supports(AuthenticationToken var1) {
return var1 instanceof UserEmailToken;
}
}
Creating a mail verification code login validates through the UserEmailToken class that generates the token (password login uses the shiro default UsernamePasswordToken token)
@Data // Use lombok Generate get Method, set Method
public class UserEmailToken implements HostAuthenticationToken, RememberMeAuthenticationToken {
private String userEmail;
private boolean rememberMe;
private String host;
public UserEmailToken() {
this.rememberMe = false;
}
public UserEmailToken(String userEmail) {
this(userEmail, false, null);
}
public UserEmailToken(String userEmail, boolean rememberMe) {
this(userEmail, rememberMe, null);
}
public UserEmailToken(String userEmail, boolean rememberMe, String host) {
this.userEmail = userEmail;
this.rememberMe = rememberMe;
this.host = host;
}
@Override
public String getHost() {
return host;
}
@Override
public boolean isRememberMe() {
return rememberMe;
}
/**
* Rewrite getPrincipal Method
*/
@Override
public Object getPrincipal() {
return userEmail;
}
/**
* Rewrite getCredentials Method
*/
@Override
public Object getCredentials() {
return userEmail;
}
}
Creating Cryptographic Salt Encryption MDPasswordUtil Tool Class
public class MDPasswordUtil {
public String getMDPasswordUtil(String userName, String userPassword) {
String hashAlgorithmName = "MD5"; // Encryption method: md5 Encryption
Object credentials = userPassword; // Password
Object salt = ByteSource.Util.bytes(userName); // Salt
int hashIterations = 512; // Encryption times
Object result = new SimpleHash(hashAlgorithmName, credentials, salt, hashIterations);
return result.toString();
}
}
Control layer user password login
// User password login
@PostMapping("/passwordLogin")
public String userLogin(@RequestParam("userName") String userName,
@RequestParam("userPassword") String userPassword,
HttpSession session, Model model) {
// Get the current user
Subject subject = SecurityUtils.getSubject();
// For the password MD5 Salt value encryption
String md5Password = new MDPasswordUtil().getMDPasswordUtil(userName, userPassword);
// Encapsulate the user's login data
UsernamePasswordToken token = new UsernamePasswordToken(userName, md5Password);
//rememberme Remember me
token.setRememberMe(true);
try {
// Login, Authenticate, Save Token
subject.login(token);
// Query login information
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.eq("user_name", userName);
User user = userService.getOne(wrapper);
// Save login user information
session.setAttribute(user.getUserId().toString(), user);
return "admin";
} catch (UnknownAccountException e) {
model.addAttribute("userError", " Wrong user name! Please re-enter. ");
return "login";
} catch (IncorrectCredentialsException ice) {
model.addAttribute("pwError", " Wrong password! Please re-enter. ");
return "login";
}
}
Control layer user mail verification code password login
// User mailbox login
@PostMapping("/emailLogin")
public String emailLogin(@RequestParam("userEmail") String userEmail,
@RequestParam("emailCode") String emailCode,
HttpSession session, Model model) {
// According to userEmail From session Take out the sent verification code from
String sendEmailCode = (String) session.getAttribute(userEmail);
// Comparison verification code
if (StringUtils.isNoneBlank(sendEmailCode) && sendEmailCode.equals(emailCode)) {
try {
UserEmailToken token = new UserEmailToken(userEmail);
//rememberme Remember me
token.setRememberMe(true);
// Login, Authenticate, Save Token
Subject subject = SecurityUtils.getSubject();
subject.login(token);
// Query login information
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.eq("user_email", userEmail);
User user = userService.getOne(wrapper);
// Save login user information
session.setAttribute(user.getUserId().toString(), user);
// Destroy verification code
session.removeAttribute(emailCode);
return "admin";
} catch (Exception e) {
model.addAttribute("error", " Verification code error! Please re-enter. ");
return "login";
}
} else {
return "login";
}
}
SpringBoot integrates Shiro password login and email verification code login (more Realm authentication) (a little more, hahaha)
Recommended great god: crazy god says Java