關於受權認證請看這篇javascript
後臺受權認證弄完了如今搞前臺。 模版是用 Angular 的ngx-admin. 效果很酷炫。java
重寫了login component, 將原有的那個google ,facebook 等第三方登入先移除掉。查看git
修改方法也很簡單,本身重新註冊這個component。github
同理 註冊頁面也是同樣的spring
國際化也已經添加 這裏就不介紹了。 數據庫
下面主要的是代碼邏輯。 建議能夠先看一下這個文檔api
const NB_CORE_PROVIDERS = [ ...DataModule.forRoot().providers, ...NbAuthModule.forRoot({ providers: { email: { service: NbEmailPassAuthProvider, config: { baseEndpoint: '/api', delay: 500, login: { rememberMe: true, endpoint: '/oauth/token', method: 'post', redirect: { success: '/', failure: null, }, defaultErrors: ['auth.login.loginError'], defaultMessages: ['auth.login.loginSuccess'], }, register: { endpoint: '/user/register', method: 'post', redirect: { success: '/', failure: null, }, defaultErrors: 'Register error', defaultMessages: 'Success', }, token: { key: 'access_token', }, }, }, }, forms: { login: { socialLinks: socialLinks, }, register: { socialLinks: socialLinks, }, }, }).providers,
提供一個provider. app
登入 /api/oauth/token ide
註冊 /api/user/registerpost
啓動的時候幾個配置 proxy,
這樣當你訪問 /api/oauth/token 它會訪問 localhost:8080/oauth/token
angular 裏面提供的http 請求時候的攔截器,在登入的時候咱們在攔截器裏面添加head 屬性
/** * Created by fky on 4/4/2018. */ import {Injectable} from '@angular/core'; import {HttpInterceptor, HttpHandler, HttpRequest, HttpEvent} from '@angular/common/http'; import {Md5} from 'ts-md5/dist/md5' import {Observable} from 'rxjs/Observable'; import 'rxjs/add/operator/do'; import {NbTokenService} from '@nebular/auth/services/token/token.service' import 'rxjs/add/operator/switchMap'; @Injectable() export class RequestInterceptor implements HttpInterceptor { constructor(private nbTokenService: NbTokenService) { } intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> { if (req.url === '/api/oauth/token') { const requestCopy = req.clone({ headers: req.headers .append('Content-Type', 'application/x-www-form-urlencoded;charset=utf-8') //spring auth token 驗證須要這個 type .append('authorization', 'Basic dGVzdGp3dGNsaWVudGlkOlhZN2ttem9OemwxMDA='), // 這個是clientid 和client_secret basic body: 'username=' + req.body.email + '&password=' + Md5.hashStr(req.body.password) + '&grant_type=password', }, ); return next.handle(requestCopy); } else if (req.url === '/api/user/register') { const requestCopy = req.clone({ body: { email: req.body.email, username: req.body.username, password: Md5.hashStr(req.body.password), confirmPassword: Md5.hashStr(req.body.confirmPassword), terms: req.body.terms, }, }, ); return next.handle(requestCopy); } else { return this.nbTokenService.get().switchMap(tokenObj => { const token = tokenObj.getValue(); const requestCopy = req.clone({ headers: req.headers .append('Authorization', 'Bearer ' + token), }); return next.handle(requestCopy); }); } } }
登入時候我把密碼MD5了一下。
登入的後臺驗證過程都是spring完成的, 咱們只是以前配置了一下。 邏輯能夠看一下源碼
類:org.springframework.security.oauth2.provider.endpoint.TokenEndpoint.class
@RequestMapping(value = "/oauth/token", method=RequestMethod.POST) public ResponseEntity<OAuth2AccessToken> postAccessToken(Principal principal, @RequestParam Map<String, String> parameters) throws HttpRequestMethodNotSupportedException { if (!(principal instanceof Authentication)) { throw new InsufficientAuthenticationException( "There is no client authentication. Try adding an appropriate authentication filter."); } String clientId = getClientId(principal); ClientDetails authenticatedClient = getClientDetailsService().loadClientByClientId(clientId); TokenRequest tokenRequest = getOAuth2RequestFactory().createTokenRequest(parameters, authenticatedClient); if (clientId != null && !clientId.equals("")) { // Only validate the client details if a client authenticated during this // request. if (!clientId.equals(tokenRequest.getClientId())) { // double check to make sure that the client ID in the token request is the same as that in the // authenticated client throw new InvalidClientException("Given client ID does not match authenticated client"); } } if (authenticatedClient != null) { oAuth2RequestValidator.validateScope(tokenRequest, authenticatedClient); } if (!StringUtils.hasText(tokenRequest.getGrantType())) { throw new InvalidRequestException("Missing grant type"); } if (tokenRequest.getGrantType().equals("implicit")) { throw new InvalidGrantException("Implicit grant type not supported from token endpoint"); } if (isAuthCodeRequest(parameters)) { // The scope was requested or determined during the authorization step if (!tokenRequest.getScope().isEmpty()) { logger.debug("Clearing scope of incoming token request"); tokenRequest.setScope(Collections.<String> emptySet()); } } if (isRefreshTokenRequest(parameters)) { // A refresh token has its own default scopes, so we should ignore any added by the factory here. tokenRequest.setScope(OAuth2Utils.parseParameterList(parameters.get(OAuth2Utils.SCOPE))); } OAuth2AccessToken token = getTokenGranter().grant(tokenRequest.getGrantType(), tokenRequest); if (token == null) { throw new UnsupportedGrantTypeException("Unsupported grant type: " + tokenRequest.getGrantType()); } return getResponse(token); }
登入成功 返回一串token 值 , 後續驗證用戶時候只要帶這串token 就能夠了。
註冊 後臺controller
@RestController @RequestMapping("/user") public class UserController { @Autowired private UserServcie userService; @RequestMapping(value = "/register", method = RequestMethod.POST) public ResponseEntity<OAuth2AccessToken> register(@RequestBody User user) throws RestException { OAuth2AccessToken token = userService.registerUser(user); HttpHeaders headers = new HttpHeaders(); headers.set("Cache-Control", "no-store"); headers.set("Pragma", "no-cache"); return new ResponseEntity<OAuth2AccessToken>(token, headers, HttpStatus.OK); } }
@Override public OAuth2AccessToken registerUser(User user) throws RestException { User u = userDAO.findByEmail(user.getEmail()); if (u != null) { throw new RestException("User email exist"); } User copy = new User(); BeanUtils.copyProperties(user, copy); // 將獲得的 md5 密碼再加密一邊存數據庫 // encode password BCryptPasswordEncoder encoder = new BCryptPasswordEncoder(); copy.setPassword(encoder.encode(user.getPassword())); userDAO.registerUser(copy); return createToken(user); } private OAuth2AccessToken createToken(User user) { Map<String,String> param = new HashMap<>(); param.put("username", user.getEmail()); param.put("password", user.getPassword()); param.put("grant_type", grantType); Set<String> scopes = new HashSet<>(); scopes.add(scopeRead); scopes.add(scopeWrite); TokenRequest tokenRequest = new TokenRequest(param, clientId, scopes, grantType); ClientDetails authenticatedClient = clientDetailsService.loadClientByClientId(clientId); //user password authentication token Authentication userAuth = new UsernamePasswordAuthenticationToken(user.getEmail(), user.getPassword()); param.remove("password"); ((AbstractAuthenticationToken) userAuth).setDetails(param); userAuth = authenticationManager.authenticate(userAuth); return tokenServices.createAccessToken(new OAuth2Authentication(tokenRequest.createOAuth2Request(authenticatedClient), userAuth)); }
寫註冊時候 成功的時候要返回token 給我一陣好整。 分析了login的整個流程,用新註冊的帳號從新模擬再登入一遍。 返回token 前臺直接跳到home page.
倉庫:https://gitee.com/codefans/fmanager
https://gitee.com/codefans/admin-cli
歡迎小夥伴加入一塊兒玩耍